Windowsの文字コードと改行コード - 文字化けとCRLF/LFの基本

· 更新日: · · Windows, 文字コード, 文字化け, 改行コード, UTF-8, CP932, PowerShell, Unicode

更新履歴(5件・最終更新 2026年08月02日)

この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。

記事の冒頭に「この記事の知識マップ」節を追加しました。本文で扱っている概念とその関係を、要約・図・詳細ページへのリンクにまとめたものです。本文の主張は変えていません。
同じバイト列が読む前提でどう変わるかの図と、表示崩れとデータ破損の分かれ目を示す図を追加しました。本文の説明は変えていません。
外部レビュー(1283件)への対応として本文を更新しました。個々の変更内容は、この下の履歴を参照してください。
対象読者と前提環境を冒頭に明示し、BOMが何でありUTF-8にも付くのはなぜかの節を追加しました。あわせてVS Code・メモ帳・PowerShellそれぞれで文字コードを確認・設定する方法をまとめています。
日本語の文中に file、editor、console、bytes、code page といった英単語がそのまま混ざっていたのを、通しで日本語(ファイル、エディタ、コンソール、バイト列、コードページ)に直しました。説明している内容そのものは変えていません。あわせて関連記事へのリンクの文言を、リンク先の現在のタイトルに揃えました。
初版公開
この記事を引用する(DOI: 10.5281/zenodo.21589797)

この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。

小村 豪(2026)「Windowsの文字コードと改行コード - 文字化けとCRLF/LFの基本」合同会社小村ソフト. https://doi.org/10.5281/zenodo.21589797 https://staging.comcomponent.com/blog/2026/04/18/000-windows-text-encoding-line-endings/

DOI(最新版)
10.5281/zenodo.21589797
DOI(この版)
10.5281/zenodo.21732812

Windows のテキストまわりの相談では、かなりの頻度で次の話が一気に混ざります。

  • Shift_JISUTF-8 は何が違うのか
  • なぜ文字化けが起きるのか
  • CRLFLF は何が違うのか
  • UTF-8 にしたのに、なぜ読めないことがあるのか
  • なぜ同じファイルなのにエディタ、コンソール、Excel、Git で見え方が変わるのか

この話は、日本語が難しいから起きるわけではありません。ほとんどは、同じバイト列を別の前提で読んだ か、読み間違えた内容をそのまま保存した ことが原因です。

さらに Windows では、Unicode の世界とコードページの世界が今も共存しています。そこへ BOM、改行コード、エディタの自動判定、コンソールのコードページ、Git の改行変換まで重なるので、話がややこしく見えます。

この記事では、Windows でよく混ざる Shift_JIS / UTF-8 / UTF-16、なぜ文字化けが起きるのか、CRLFLF の違い、そしてなぜこの話が混乱しやすいのかを、実務向けに整理します。

内容は 2026 年 4 月時点の Microsoft Learn、PowerShell、Git、W3C / Unicode 系の公開情報を前提にしています。詳細は末尾の参考資料を参照してください。

対象読者・前提環境

項目 内容
対象読者 Windows でテキストファイル (CSV、ログ、設定ファイル、ソースコード) を他部署・他システム・Linux 側とやり取りする開発者、情シス担当
前提知識 特にありません。バイト列と文字コードの区別が付いていない状態から読める構成にしています
前提環境 Windows 10 / Windows 11。PowerShell は Windows PowerShell 5.1 と PowerShell 7 の両方に触れます
扱わないこと 個別のライブラリごとの文字コード変換 API の使い方、フォント / グリフの設計、全角半角などの正規化

急いでいる場合の読み方は次のとおりです。全体像だけなら 1 章と 2 章、原因の切り分けだけなら 3 章と 8 章、運用ルールを決めたいなら 7 章から読んでください。

目次

  1. まず押さえたいこと
  2. 用語を分解する
    • 2.1 Unicode / UTF-8 / UTF-16 / CP932 は何が違うのか
    • 2.2 Shift_JISCP932 をどう考えるか
    • 2.3 ANSIUnicodeUTF-8N という言葉の罠
    • 2.4 BOM とは何か、なぜ UTF-8 にも付くのか
  3. なぜ文字化けが起きるのか
    • 3.1 文字化けの正体
    • 3.2 表示崩れとデータ破損は別
    • 3.3 表現できない文字へ落とすと戻らない
  4. 改行文字の違いとは
    • 4.1 CRLF / LF / CR
    • 4.2 改行は文字コードとは別問題
    • 4.3 \n とファイル上の改行バイト列は同じとは限らない
  5. なぜ Windows では特に混乱しやすいのか
    • 5.1 Unicode とレガシーコードページが共存している
    • 5.2 ラベルが揃っていない
    • 5.3 ASCII だけだと問題が隠れる
    • 5.4 ファイルの中身、ファイル名、コンソール、ソースファイルは別レイヤ
    • 5.5 BOM と改行コードも別軸で効く
    • 5.6 ツールが勝手に変える
  6. よくある事故パターン
  7. 実務で事故を減らすルール
  8. 文字化け・行末差分の調査はこの 5 問で進める
  9. まとめ
  10. 関連記事
  11. 参考資料

この記事の知識マップ

Windowsのテキストはバイト列・文字コード・改行コード・BOMという別々の軸の組み合わせで成り立ち、UTF-8やUTF-16LEはUnicodeの符号点をバイト列にする文字コードである一方、CP932は日本語Windows独自のレガシーコードページで両者は前提を取り違えると文字化けを起こす。BOMはUTF-16のバイト順を示す目印であると同時に、UTF-8では「UTF-8である」というシグネチャとして使われ、Windows PowerShell 5.1は非ASCII文字を含むスクリプトを正しく読むためにBOMを必要とする。改行コードはCRLFとLFのどちらかで文字コードとは別問題であり、リポジトリ単位の扱いは.gitattributesで固定できるが、Gitは改行こそ変換しても文字コードは自動で正してくれない。文字化けは正しい文字コードで開き直せば戻ることが多いが、誤読した内容をそのまま保存すると元のバイト列が失われ、表示崩れではなく取り返しのつかないデータ破損になる。

Windowsの文字コードと改行コードの知識マップUnicodeとUTF-8・UTF-16LE・CP932の関係、BOMの役割、文字化けとデータ破損の違い、PowerShellの既定値やGitの改行変換が改行コードと文字コードそれぞれにどう効くかを示す図。利用する利用する利用する利用する利用する利用する原因になり得る実装を担う実装を担う両立しない原因になり得る両立しない両立しない利用する利用する利用する前提とするで構成できる原因になり得る文字コード(キャラクターエンコーディング)改行コードUnicodeUTF-8UTF-16LECP932アクティブコードページ(ANSI/ACP)BOM(Byte Order Mark)文字化けPowerShellの文字コード既定値.gitattributes誤読内容の再保存によるデータ破損

図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全19件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle

1. まず押さえたいこと

先に結論だけ並べると、重要なのは次の 7 点です。

  • テキストファイルは、文字列そのもの ではなく、バイト列 + 文字コード + 改行コード で成り立っています。場合によっては BOM (Byte Order Mark、バイト順マーク) も付きます。
  • 文字化けは、同じバイト列を別の文字コードとしてデコードした ときに起きます。
  • 改行トラブルは、文字コードが正しくても行区切りの前提がずれている ときに起きます。
  • UnicodeUTF-8 は同じ意味ではありません。Unicode は文字集合側の話で、UTF-8UTF-16 はそれをバイト列にする文字コードの話です。
  • Windows で「Shift_JIS」と呼ばれているものは、実務では CP932 / Windows 系の日本語コードページ と意識したほうが会話がぶれにくいです。
  • UTF-8 にした だけでは、まだ仕様として足りません。BOM の有無改行コード まで決めて初めて運用ルールになります。
  • 混乱の元は、日本語そのもの ではなく、歴史の違う複数の前提が同じ Windows 上に残っていること です。

Windows のテキストを扱うときは、まず次の 4 つを分けて考えるのが出発点です。

  1. そのファイルのバイト列は何か
  2. どの文字コードで書かれたか
  3. どの文字コードで読まれたか
  4. 改行は CRLF / LF のどちらか

ここが分かれるだけで、かなり迷いにくくなります。

2. 用語を分解する

2.1 Unicode / UTF-8 / UTF-16 / CP932 は何が違うのか

まず、言葉を 1 回分解したほうが早いです。

用語 何を指すか よくある混同
Unicode 文字を番号で表すための枠組み U+3042 () UTF-8 と同じものだと思う
UTF-8 Unicode をバイト列にする文字コード E3 81 82 Unicode 自体だと思う
UTF-16LE Unicode をバイト列にする文字コード 42 30 メニュー上の Unicode 表記と混ざる
CP932 Windows 日本語系のレガシーコードページ 82 A0 Shift_JIS と完全に同じだと思う
CRLF / LF 行の区切りのバイト列 0D 0A / 0A 文字コードの一種だと思う
BOM (Byte Order Mark) ファイル先頭の識別用バイト列 EF BB BF など 文字コード名そのものだと思う

たとえば という 1 文字でも、バイト列は文字コードごとに違います。

文字: あ

UTF-8    : E3 81 82
CP932    : 82 A0
UTF-16LE : 42 30

大事なのは、文字とバイト列は別物 だということです。アプリは画面上では「文字」に見えるものを扱っていますが、保存や通信では最終的にバイト列をやり取りします。事故はだいたい、その変換の境界で起きます。

2.2 Shift_JISCP932 をどう考えるか

現場では、日本語 Windows のテキストファイルをまとめて「Shift_JIS」と呼ぶことが多いです。会話としては通じますが、実務では少し雑です。

Windows の日本語のレガシーなテキストを正確寄りに意識するなら、CP932、あるいは Windows 系の日本語コードページ と考えたほうが安全です。

ここを雑にすると、次のような会話がぶれます。

  • Shift_JIS で保存して と言ったが、相手は Windows 側の CP932 を想定していた
  • Linux / macOS 側では shift_jis として扱ったが、Windows 由来のファイルの一部で再現が合わない
  • ANSI 保存と言われたが、どのコードページかは環境依存だった

なので、仕様や調査メモでは、できるだけ次のように書くほうが安全です。

  • Shift_JIS ではなく CP932
  • ANSI ではなく ACP (active code page) / 日本語環境では通常 CP932
  • テキスト ではなく UTF-8 no BOM, LF のように具体化する

2.3 ANSIUnicodeUTF-8N という言葉の罠

Windows まわりでは、言葉のラベルも混乱の原因です。

特に紛らわしいのはこの 3 つです。

  • ANSI Windows の UI や古い説明で出てきますが、ASCII ではありません。多くの場合は そのマシンのアクティブコードページ (ACP) を指します。
  • Unicode 一部のエディタやツールでは、メニュー上の UnicodeUTF-16LE を意味することがあります。Unicode で保存した と言われても UTF-8 とは限りません。
  • UTF-8N 日本語圏のエディタで見かけることがありますが、これはふつう UTF-8 no BOM を区別するための UI ラベルです。文字コードの正式名称ではありません。

つまり、同じ言葉でもツールごとに意味がずれる のが Windows です。ここが、最初の大きな混乱ポイントです。

2.4 BOM とは何か、なぜ UTF-8 にも付くのか

BOM は Byte Order Mark (バイト順マーク) の略で、ファイルやストリームの先頭に置かれる U+FEFF という符号のことです。名前のとおり、本来の役割は バイトの並び順を示すこと です。

UTF-16 や UTF-32 は 2 バイト / 4 バイトをひとかたまりとして文字を表すため、そのかたまりを「下位バイトから並べるか (リトルエンディアン)」「上位バイトから並べるか (ビッグエンディアン)」を読む側へ伝える必要があります。そこで先頭に BOM を置き、その BOM のバイトの並び順で、以降も同じ並び順であることを示します。

先頭のバイト列 意味
FF FE UTF-16 リトルエンディアン
FE FF UTF-16 ビッグエンディアン
EF BB BF UTF-8

ここで疑問になるのが、UTF-8 は 1 バイト単位なので並び順の問題がないはずなのに、なぜ BOM が付くのか です。

理由は、UTF-8 の BOM がバイト順ではなく 「このファイルは UTF-8 です」という目印 (シグネチャ) として使われているからです。UTF-8 は ASCII と互換なので、中身が英数字だけだとレガシーコードページとの区別が付きません。先頭に EF BB BF を置いておけば、読む側は「アクティブコードページではなく UTF-8 として読めばよい」と判断できます。

裏を返すと、次のようになります。

  • BOM を付ける利点: 読む側が文字コードの推測に失敗しにくくなります。特に Windows PowerShell 5.1 は、BOM のないスクリプトファイルをアクティブコードページとして読むため、非 ASCII 文字を含むスクリプトは BOM がないと壊れます。
  • BOM を付ける欠点: 先頭に 3 バイトの余計なデータが増えます。BOM を知らない処理系では、1 行目の先頭に見えない文字が混ざったように扱われます。CSV のヘッダの 1 列目だけ名前が一致しない、シェルスクリプトの #! 行が認識されない、といった事故はここから起きます。

つまり、UTF-8 の BOM は「付けるのが正しい / 間違っている」という話ではなく、読む側が誰かで決める設定項目 です。だからこそ 7.1 のように、「UTF-8 にする」だけでなく「with BOM か no BOM か」まで決める必要があります。

3. なぜ文字化けが起きるのか

3.1 文字化けの正体

文字化けの正体は、かなり単純です。

  1. 文字列を、ある文字コードでバイト列にする
  2. そのバイト列を、別の文字コードで文字列へ戻す
  3. 前提が一致していなければ、別の文字列になる

たとえば を UTF-8 で保存すると、バイト列はこうなります。

E3 81 82

これを UTF-8 として読めば ですが、CP932 側の前提で読めば 縺� のような別の文字列に見えます。 このとき壊れているのは「日本語」ではなく、デコードの前提 です。

文字化けを 1 行で言うなら、こうです。

同じバイト列を、違う文字コードとして読んだ。

UTF-8 でエンコードして保存UTF-8 としてデコードCP932 としてデコード文字 あバイト列 E3 81 82ファイルに入っているのはこれだけ文字 あ ── 前提が一致している縺 のような別の文字列 ── 前提がずれている

図1: 2つの分かれ道でファイルの中身(バイト列)は同じ。違うのは読む側が置いた前提だけ

3.2 表示崩れとデータ破損は別

ここで大事なのは、まだ戻せる段階もう戻しにくい段階 を分けることです。

たとえば次の流れなら、まだ戻せる可能性があります。

  1. UTF-8 のファイルを CP932 として開く
  2. 画面上では 縺� のように見える
  3. まだ保存していない

この段階では、元のバイト列は UTF-8 のまま残っています。正しい文字コードで開き直せば戻ることがあります。

危ないのはこの流れです。

  1. UTF-8 のファイルを CP932 として誤読する
  2. 壊れて見えている内容を、そのまま保存する
  3. もとの UTF-8 のバイト列が失われる

ここまで行くと、表示崩れではなくデータ破損 です。

CP932 の前提で開く開き直すそのまま保存するUTF-8 で保存されたファイルバイト列は E3 81 82画面には 縺 のように見える= 表示崩れ。バイト列はまだ UTF-8 のまま正しい文字コードを指定すれば元に戻る誤読した文字列を CP932 で書き戻す= データ破損。元のバイト列が失われるあとから正しい文字コードが分かっても戻らない

図2: 分かれ目は「開き直したか、保存したか」の一手だけ。調査では必ずここを先に確認する

実務では、「文字化けした」という 1 文でまとめずに、少なくともこの 2 つを分けるのが大事です。

  • バイト列自体はまだ正しいのか
  • 誤読した内容がすでに再保存されたのか

3.3 表現できない文字へ落とすと戻らない

もう 1 つ危ないのは、Unicode 文字列を CP932 のような狭いコードページに落とすときです。

このとき、相手側に存在しない文字が含まれていると、次のどれかが起きます。

  • ? に置き換わる
  • 置換文字が入る
  • 変換エラーになる
  • 別の近い文字へ寄せられる

たとえば、一部の絵文字や拡張漢字は CP932 へそのまま落とせません。 この事故は「読めるかどうか」ではなく、往復変換して元に戻るか で考えるべきです。

一度失われた情報は、あとから正しい文字コードを知っても元に戻りません。

4. 改行文字の違いとは

4.1 CRLF / LF / CR

改行もバイト列です。

  • CR = carriage return = 0D
  • LF = line feed = 0A
  • Windows のテキストファイルでは CRLF (0D 0A) が伝統的
  • Linux / Unix 系では LF (0A) が一般的
  • CR 単独は旧 Mac 系などの古い文脈で出ることがある

表にするとこうです。

改行 バイト列 主な文脈
CRLF 0D 0A Windows の従来のテキストファイル、レガシーツール
LF 0A Linux / macOS / 多くの開発ツール
CR 0D かなり古いレガシーデータ

4.2 改行は文字コードとは別問題

ここがかなり重要です。

改行コードは文字コードとは別問題 です。

同じ UTF-8 のファイルでも、改行は CRLF にも LF にもなります。 たとえば A、改行、B という内容ならバイト列は次のように変わります。

UTF-8 + LF   : 41 0A 42
UTF-8 + CRLF : 41 0D 0A 42

つまり、

  • UTF-8 なのに改行だけ違う
  • CP932 なのに改行は LF
  • UTF-16LE なのに改行は CRLF

は普通にありえます。

なので、UTF-8 にしたのにまだ違う というとき、実際には 文字コードではなく改行だけがずれている ことがあります。

4.3 \n とファイル上の改行バイト列は同じとは限らない

プログラマ視点で地味に混乱しやすいのがここです。

ソースコードの中で \n と書いたからといって、ファイル上に必ず 0A だけが出るとは限りません。 言語やランタイム、I/O API の テキストモード では、Windows 上で \nCRLF に変換されることがあります。

つまり、次がずれる可能性があります。

  • ソースコード上の改行表現
  • 実行時の文字列
  • ファイルに保存されたバイト列
  • エディタ上で見える改行

このため、「自分は LF を書いたつもりだったのにファイルは CRLF だった」という事故が起きます。

最近のエディタは LF 単独を普通に扱えますが、周辺ツール、レガシーアプリ、業務運用はまだ CRLF 前提が残っています。 そのため、改行問題は「昔の話」ではなく、今も実務で普通に出ます。

5. なぜ Windows では特に混乱しやすいのか

5.1 Unicode とレガシーコードページが共存している

Windows がややこしい最大の理由はこれです。

Windows には、

  • Unicode を使う道
  • コードページベースで扱う道

の両方が残っています。

新しめのアプリ、Web、クロスプラットフォーム系の資産は UTF-8 へ寄りやすい一方で、古い CSV、TXT、ログ、Excel 周辺、業務システム連携では CP932 が残っています。 さらに、一部の出力や API 周辺では UTF-16LE も普通に出ます。

つまり、1 台の Windows の中に複数のテキスト文化が同居している のです。

5.2 ラベルが揃っていない

混乱を増やすのは、技術そのものよりもラベルのずれです。

  • Shift_JIS と言っているが、実態は CP932
  • ANSI と言っているが、実態はアクティブコードページ
  • Unicode と言っているが、実態は UTF-16LE
  • UTF-8 と言っているが、実際には BOM あり / なしが未確定
  • UTF-8N のようなエディタ独自ラベルが出てくる

ここを曖昧にすると、会話では通じているように見えて、実体が揃っていません。

5.3 ASCII だけだと問題が隠れる

これも大きいです。

UTF-8 は ASCII 範囲と互換性があるため、英数字と記号だけのファイルは、間違った前提でも「何となく読めてしまう」ことがあります。 CP932 側でも ASCII 相当の範囲は見た目が壊れにくいので、問題が表面化しません。

その結果、こんな状態になります。

  • 英語だけの設定ファイルは問題なく見える
  • 日本語を 1 行入れた瞬間に壊れる
  • ずっと潜んでいた問題が、運用中に初めて発火する

だから文字コード事故は、「昨日まで動いていたのに、今日から急に壊れた」ように見えやすいです。 実際には、前から地雷はあって、非 ASCII 文字が入った瞬間に見えただけ ということが多いです。

5.4 ファイルの中身、ファイル名、コンソール、ソースファイルは別レイヤ

Windows では、次をまとめて「文字コード」と呼ぶと迷います。

  • ファイル名 / パス
  • ファイルの中身
  • コンソールへの表示
  • ソースコードファイル自体の文字コード
  • 実行時の文字列形式
  • クリップボードや GUI 部品上の表示

たとえば、日本語のファイル名が普通に見えていても、ファイルの中身は CP932 で保存されているかもしれません。 逆にファイル自体は UTF-8 でも、コンソールのコードページが合っていなければ表示だけ壊れます。

chcp 65001 のような操作も、基本的にはコンソール側の前提に効く話であって、既存ファイルのバイト列を変える話ではありません。

さらに、ソースコードファイルが UTF-8 でも、実行時に書き出すログファイルが UTF-8 とは限りません。 どの層の文字コードの話をしているか を毎回分ける必要があります。

なお、日本語 Windows では \ が円記号に見えることがあり、これも文字コードの話と混ざりやすいです。 ただし多くの場合、これは 表示フォントやグリフの問題 であって、パス区切りやエスケープの意味が変わったわけではありません。

5.5 BOM と改行コードも別軸で効く

UTF-8 という言い方だけでは、まだ半分しか決まっていません。

実務では、次も効きます。

  • BOM はあるか、ないか
  • 改行は CRLFLF

たとえば、同じ UTF-8 でも、

  • BOM ありなら読める Windows ツールがある
  • BOM があると先頭列に余計な文字が乗る Unix 系処理がある
  • LF だけだとレガシー側で扱いにくいツールがある
  • CRLF だとシェルスクリプトや diff が荒れることがある

という具合に、文字コードが合っていてもまだ事故る のです。

5.6 ツールが勝手に変える

さらに厄介なのが、手元のツールが暗黙に変えることです。

  • エディタが自動判定する
  • 保存時に BOM を付ける / 外す
  • Git が CRLF / LF を変換する
  • シェルやコマンドが既定の文字コードで保存する
  • CSV エクスポートが想定外のコードページを使う
  • 別バージョンの PowerShell やツールで既定値が違う

つまり、作業者が明示していなくても、どこかの層が勝手に前提を足してくる のが Windows 実務です。

これが「自分は何も変えていないのに壊れた」の正体です。 実際には、人ではなく ツールの既定値 が変えていることが少なくありません。

6. よくある事故パターン

典型事故を表にすると、次のようになります。

場面 実際にずれているもの 典型症状
UTF-8 no BOM の設定ファイルをレガシーな Windows ツールが ANSI / CP932 とみなす デコード前提 日本語だけ文字化けする
CP932 の CSV を UTF-8 前提の処理系へ渡す デコード前提 、デコードエラー、意味不明な日本語
UTF-16LE のログを Unix 系のテキストツールへ渡す 文字コード前提 NUL バイトが混ざり、バイナリっぽく見える
LF のソースファイルを別環境で CRLF へ変換する 改行前提 巨大な行末差分、スクリプトの不具合
誤読した内容をそのまま保存する バイト列自体が別物になる 元に戻せないデータ破損
CSV を出して とだけ仕様を書く インターフェースが未定義 Excel では読めるが別ツールでは壊れる
UTF-8 に統一 とだけ決める BOM / 改行が未定義 一部のツールだけ失敗する

特に危ないのは、表示崩れを見たあと、そのまま保存して事故を確定させる パターンです。

7. 実務で事故を減らすルール

ここからは、運用ルールとして何を決めると事故が減るかです。

7.1 新規テキストの基本線を決める

新規ファイルでは、まず UTF-8 を第一候補にするのが妥当です。 ただし、それだけでは足りません。

最低限、次まで決めたほうが安全です。

  • UTF-8 with BOMUTF-8 no BOM
  • 改行は CRLFLF
  • 誰が読むファイルなのか
  • レガシーな Windows ツールとの互換が必要か
  • Linux / macOS / CI / コンテナも読むのか

たとえば、クロスプラットフォーム前提のソースコードや設定ファイルなら、UTF-8 no BOM + LF が第一候補になりやすいです。 一方で、Windows の古いツールや既存運用へ合わせる必要があるなら、UTF-8 with BOMCP932 + CRLF がまだ必要なこともあります。

重要なのは、「何が正しいか」の一般論より、誰とやり取りするか で決めることです。

7.2 既存のレガシーファイルは勝手に変えない

既存のファイルが CP932 なら、日常の小修正のついでに UTF-8 化しないほうが安全です。

安全側の運用はこうです。

  • 既存ファイルは、元の文字コード / BOM / 改行を維持する
  • 文字コード変換は、別の移行タスクとして分ける
  • 変換対象と下流の利用側を確認してから一括変換する

文字化け事故は、善意の「ついでにモダン化」から起きがちです。

7.3 文字コードと改行をインターフェースの一部として扱う

CSV、TXT、ログ、設定ファイル、簡易プロトコルは、内容だけでなくテキスト形式自体がインターフェース です。

仕様には、最低でも次を書いたほうが安全です。

  • 文字コード
  • BOM の有無
  • 改行コード
  • ヘッダの有無
  • 引用符 / 区切り文字の仕様
  • どのツールで検証したか

たとえば CSV という 3 文字だけでは不十分です。 UTF-8 with BOM, CRLF, カンマ区切り, ヘッダあり まで書いて初めて、会話がずれにくくなります。

7.4 読み書きの境界では明示する

コード側でも、暗黙の既定値に寄せないほうが安全です。

  • ファイルの読み書き時は文字コードを明示する
  • プロセス間のテキスト受け渡しでも文字コードを意識する
  • エクスポート / インポート処理では改行も仕様として固定する
  • シェルの雑なリダイレクトを本番経路にしない

特に Windows では、「保存できた」ことと「正しいバイト列で保存できた」ことは同じではありません。

7.5 Git とエディタのルールも共有する

Git は文字コードを自動で正してくれる道具ではありません。 一方で、改行コードについては変換が入ることがあります。

なので、リポジトリ単位で次を決めたほうが安全です。

  • ソースコードは LF を基本にするか
  • Windows 専用のテキストは CRLF を許容するか
  • .gitattributes でどう固定するか
  • エディタ設定をどう共有するか

文字コードと改行コードを別々に考えることが重要です。 Git が改行をそろえてくれても、文字コードの事故はそのまま残ります。

7.6 「文字化けした」で止まらず、何がずれたか言う

現場では、この言い換えがよく効きます。

  • 悪い言い方: 文字化けしました
  • 良い言い方: UTF-8 no BOM のファイルを CP932 前提で開いているように見えます
  • 悪い言い方: 行末がおかしいです
  • 良い言い方: LF のファイルが CRLF へ変換されて差分が増えています

何がずれたかが言えるだけで、調査速度はかなり変わります。

7.7 確認するには - ツール別の見どころ

ここまでのルールは、確認手段とセットにして初めて回ります。よく使う 3 つについて、「今の文字コードをどこで見るか」「どこで変えるか」をまとめます。

ツール 今の文字コードを見る場所 変える場所
VS Code ウィンドウ右下のステータスバー。UTF-8 のような文字コードと、CRLF / LF の改行表示が並びます ステータスバーの文字コード表示をクリックすると、開き直しと保存の選択肢が出ます。既定値は設定画面の files.encoding
メモ帳 ステータスバーにドキュメントのエンコードが表示されます 「ファイル」から「名前を付けて保存」を開き、ダイアログの「エンコード」欄で選びます
PowerShell ファイルの先頭バイトを直接見るのが確実です (下記のコマンド) 書き出す側のコマンドレットの -Encoding パラメーター。既定値は $PSDefaultParameterValues

VS Code

VS Code の既定の文字コードは UTF-8 (BOM なし) です。ファイルごとに変えるときはステータスバーの表示をクリックし、いま開いているファイルを別の文字コードで 開き直す のか、別の文字コードで 保存し直す のかを選びます。誤読しただけならまず開き直す、というのが 3.2 の判断と対応します。

既定値を変えるときは設定の files.encoding を指定します。値は utf8 (BOM なし)、utf8bom (BOM あり)、utf16lewindows1252 などです。言語ごとに分けることもできます。

{
  "files.encoding": "utf8",
  "[powershell]": {
    "files.encoding": "utf8bom"
  }
}

Windows PowerShell 5.1 で動かすスクリプトだけ BOM ありにする、という 2.4 の使い分けは、この言語別設定で表現できます。

メモ帳

Windows 10 の Build 18963 以降のメモ帳は、ステータスバーにドキュメントのエンコードを表示する列を持ち、新規ファイルの既定が UTF-8 (BOM なし) になっています。保存時は「ファイル」から「名前を付けて保存」を開き、ダイアログの「エンコード」欄で選びます。この欄では BOM の有無まで選べるので、7.1 で決めた方針をここで反映します。

「メモ帳で開いたら文字化けした」という報告のときは、この欄と、ステータスバーの表示を先に確認すると早いです。

PowerShell

PowerShell の既定はバージョンで大きく違います。ここを知らないまま「PowerShell で出力したらツールが読めない」という相談になることがよくあります。

  • PowerShell 6 以降 (PowerShell 7 系): すべてのテキスト出力の既定が utf8NoBOM、つまり UTF-8 の BOM なし です。
  • Windows PowerShell 5.1: 既定がコマンドレットごとに揃っていません。

5.1 の主なものを表にすると、次のようになります。

コマンド 書き出し時の既定
Out-File、リダイレクト演算子 > >> UTF-16LE
Set-ContentAdd-Content (出力先が空、または存在しないとき) Default (アクティブコードページ。日本語環境では CP932)
Export-Csv Ascii
Start-Transcript UTF-8 with BOM
New-Item -Type File -Value UTF-8 no BOM

読み込み側にも既定があります。BOM がないとき、Get-Content と PowerShell エンジンがスクリプトファイルを読むときは Default (アクティブコードページ) とみなし、Import-CsvSelect-String は UTF-8 とみなします。同じファイルでも、どのコマンドレットで読むかで前提が変わる ということです。

いま手元のファイルに BOM が付いているかは、先頭バイトを見れば分かります。

# PowerShell 7: 先頭 3 バイトを 16 進で表示する
Get-Content -Path .\sample.txt -AsByteStream -TotalCount 3 | Format-Hex

# Windows PowerShell 5.1 には -AsByteStream がないので -Encoding Byte を使う
Get-Content -Path .\sample.txt -Encoding Byte -TotalCount 3 | Format-Hex

先頭が EF BB BF なら UTF-8 with BOM、FF FE なら UTF-16LE、それ以外なら BOM なしです。2.4 の表と同じ見方です。

既定を明示的に固定したい場合は、$PSDefaultParameterValues を使います。

# Encoding パラメーターを持つすべてのコマンドレットの既定を UTF-8 にする
$PSDefaultParameterValues['*:Encoding'] = 'utf8'

ここに バージョン間の落とし穴 があります。utf8 という同じ文字列でも、Windows PowerShell 5.1 では UTF-8 with BOM、PowerShell 6 以降では UTF-8 no BOM を意味します。BOM の有無まで固定したいなら、PowerShell 6 以降で使える utf8BOM / utf8NoBOM を明示するほうが安全です。

なお、$OutputEncoding外部プログラムとの受け渡しに使う文字コード で、リダイレクトやコマンドレットがファイルへ保存するときの文字コードには影響しません。ここは混同しやすいところです。

8. 文字化け・行末差分の調査はこの 5 問で進める

調査で迷ったら、次の 5 問に戻るのが一番早いです。

  1. 今このファイルのバイト列は何か
    • UTF-8 か
    • UTF-8 with BOM か
    • CP932 か
    • UTF-16LE か
  2. 最初に誰が、どの前提で書いたか
    • エディタ
    • レガシーアプリ
    • Excel のエクスポート
    • シェル / スクリプト
    • バッチ / ミドルウェア
  3. 今誰が、どの前提で読んでいるか
    • エディタの自動判定
    • コンソールのコードページ
    • ライブラリの既定の文字コード
    • インポート側の仕様
  4. BOM と改行は何か
    • BOM あり / なし
    • CRLF / LF
  5. 誤読した内容が、すでに保存されたか
    • まだ表示だけか
    • すでに再保存されてバイト列が失われたか

この 5 問が埋まると、たいてい原因は見えてきます。

9. まとめ

Windows の文字コードと改行コードがややこしく見えるのは、日本語そのものが難しいからではありません。 バイト列、文字コード、BOM、改行コード、ツールの既定値 が別々に存在し、そのうえで Windows には新旧のテキスト文化が同居しているからです。

特に覚えておきたいのはこの 6 点です。

  • 文字化けは、同じバイト列を別の文字コードとして読んだ結果
  • 改行問題は、文字コードとは別軸の話
  • Shift_JISCP932ANSIUnicode という言葉はそのまま信用しすぎない
  • UTF-8 にした だけでは不十分で、BOM と改行も必要
  • 表示崩れと、再保存済みのデータ破損は分けて考える
  • 仕様では テキスト ではなく UTF-8 no BOM, LF のように書く

要するに、Windows のテキストを扱うときは「文字列の話」ではなく、バイト列の約束をどう揃えるか の話だと考えるのが実務的です。

10. 関連記事

11. 参考資料

  1. Microsoft Learn, Code Page Identifiers - Win32 apps https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
  2. Microsoft Learn, about_Character_Encoding - PowerShell https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-7.6
  3. Microsoft Learn, Understanding file encoding in VS Code and PowerShell https://learn.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding?view=powershell-7.6
  4. W3C Internationalization, Character encodings: Essential concepts https://www.w3.org/International/articles/definitions-characters/
  5. Git documentation, gitattributes https://git-scm.com/docs/gitattributes
  6. Git documentation, git-config https://git-scm.com/docs/git-config
  7. Microsoft Learn, The Unicode standard - Globalization (BOM のバイト列と、UTF-8 の BOM がシグネチャとして使われること) https://learn.microsoft.com/en-us/globalization/encoding/unicode-standard
  8. Microsoft Learn, What was new in 20H1 Windows 10 Insider Preview Builds (Build 18963 でのメモ帳の UTF-8 既定化と、ステータスバーへのエンコード表示の追加) https://learn.microsoft.com/en-us/previous-versions/windows-insider/archive/new-in-20h1

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

文字化けはなぜ起きるのですか?
同じバイト列を、書かれたときと違う文字コードで読んだからです。たとえば「あ」をUTF-8で保存するとE3 81 82というbytesになりますが、これをCP932の前提で読むと「縺」のような別の文字列に見えます。このとき壊れているのは日本語ではなく、decodeの前提です。ただし、誤読した内容をそのまま再保存すると元のbytesが失われ、表示崩れではなくデータ破損になるため、保存前に正しいencodingで開き直すことが重要です。
CRLFとLFの違いは何ですか?
行の区切りに使うbytesの違いです。CRLFは0D 0Aの2バイトでWindowsのテキストファイルで伝統的に使われ、LFは0Aの1バイトでLinux / macOSや多くの開発ツールで一般的です。重要なのは、改行コードは文字コードとは別問題だという点です。同じUTF-8のファイルでも改行はCRLFにもLFにもなるため、「UTF-8にしたのにまだ違う」というときは、encodingではなく改行だけがずれていることがあります。
Shift_JISとCP932は同じものですか?
会話としては通じますが、実務では区別したほうが安全です。日本語Windowsのlegacyテキストを正確に意識するなら、CP932あるいはWindows系の日本語code pageと考えます。同様に、Windowsで「ANSI」は多くの場合そのマシンのactive code pageを指し、editorのメニューにある「Unicode」はUTF-16LEを意味することがあります。仕様や調査メモでは「UTF-8 no BOM, LF」のように具体的に書くと会話がずれにくくなります。
テキストファイルの仕様は何を決めておけばよいですか?
「UTF-8にした」だけでは足りず、BOMの有無と改行コードまで決めて初めて運用ルールになります。CSVやログのような受け渡しファイルでは、encoding、BOMの有無、改行、ヘッダの有無、区切り文字の仕様まで書くのが安全です。cross-platform前提のソースコードや設定ならUTF-8 no BOM + LFが第一候補になりやすい一方、Windowsの古いツールに合わせる必要があるならUTF-8 with BOMやCP932 + CRLFがまだ必要なこともあります。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る