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)

以下のDOIは過去に登録されたアーカイブを指しており、現在の本文とは一致しない場合があります。現在の本文を参照するときは、このページのURLを使用してください。

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

DOI(登録済みアーカイブ)
10.5281/zenodo.21589797
DOI(前回登録した版)
10.5281/zenodo.21732812

CSV の日本語だけが読めない。文字は読めるのに、Git の差分がファイル全体に広がる。同じファイルでも、エディタ、コンソール、Excel で見え方が違う。こうした問題を、まとめて「文字化け」と呼ぶと調査の出発点がずれてしまいます。

まず分けたいのは、バイト列をどの文字コードで読むかと、行の区切りをどう扱うかです。さらに BOM の有無とツールの既定値を確認すると、「UTF-8 にしたのに読めない」という問題も切り分けやすくなります。

文字化けしたファイルは、原因を確かめる前に上書き保存しないでください。 元のバイト列が残っていれば正しい文字コードで開き直せる場合がありますが、誤読した内容を再保存して情報を失うと、表示だけの問題ではなくなります。

この記事では、Windows で混ざりやすい Shift_JIS / CP932 / UTF-8 / UTF-16 と CRLF / LF を分け、表示崩れとデータ破損の判断から、ツール別の確認方法、受け渡しのルールまでを整理します。Unicode とレガシーなコードページが共存する Windows では、名前だけでなく、書く側と読む側の前提をそろえることが大切です。

内容は 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〜5 章で原因、6〜8 章で対処と運用を確認してください。調査中の場合は、次の案内から必要な説明へ進めます。

知りたいこと・症状 読むところ
Unicode、UTF-8、Shift_JIS、CP932 の違いを知りたい 1 章: 全体像、2 章: 用語
日本語が文字化けした。保存してよいか迷っている 3.2 節: 表示崩れとデータ破損、8 章: 調査の 5 問
一部の絵文字や漢字だけ ? になる 3.3 節: 表現できない文字への変換
UTF-8 なのに先頭列やスクリプトだけ失敗する 2.4 節: BOM、6 章: 事故パターン
文字は読めるが、改行や Git の差分がおかしい 4 章: 改行、7.5 節: Git とエディタ
エディタでは読めるのに、コンソールでは壊れる 5.4 節: ファイルと表示先の区別
VS Code・メモ帳・PowerShell のどこを確認するか知りたい 7.7 節: ツール別の確認方法、PowerShell の版差
CSV・ログ・設定ファイルの受け渡しルールを決めたい 7 章: 運用ルール、7.3 節: インターフェースの仕様

目次

  1. まず押さえたいこと
  2. 用語を分解する — Unicode、UTF-8、UTF-16、CP932、BOM
  3. なぜ文字化けが起きるのか — 読む前提と、情報が失われる境界
  4. 改行文字の違いとは — CRLF / LF / CR とテキストモード
  5. なぜ Windows では特に混乱しやすいのか — 共存する形式とツールの既定値
  6. よくある事故パターン
  7. 実務で事故を減らすルール — 新規・既存ファイル、Git、ツール別の確認方法
  8. 文字化け・行末差分の調査はこの 5 問で進める
  9. まとめ
  10. 関連記事
  11. 参考資料

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

1. まず押さえたいこと

押さえたいのは、読む前提のずれと、形式の決め方です。まずは次の 7 点を二つに分けて見てください。

文字化けと改行トラブルを分ける

  • テキストファイルは、文字列そのもの ではなく、バイト列 + 文字コード + 改行コード で成り立っています。場合によっては BOM (Byte Order Mark、バイト順マーク) も付きます。
  • 文字化けは、同じバイト列を別の文字コードとしてデコードした ときに起きます。
  • 改行トラブルは、文字コードが正しくても行区切りの前提がずれている ときに起きます。

名前だけでファイル形式を決めたことにしない

  • Unicode と UTF-8 は同じ意味ではありません。Unicode は文字集合側の話で、UTF-8 や UTF-16 はそれをバイト列にする文字コードの話です。
  • Windows で「Shift_JIS」と呼ばれているものは、実務では CP932 / Windows 系の日本語コードページ と意識したほうが会話がぶれにくいです。
  • UTF-8 にした だけでは、まだ仕様として足りません。BOM の有無 と 改行コード まで決めて初めて運用ルールになります。
  • 混乱の元は、日本語そのもの ではなく、歴史の違う複数の前提が同じ Windows 上に残っていること です。

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

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

この四つを分けてから、BOM の有無と利用するツールを確認します。以下の章では、それぞれがどこで食い違うかを見ていきます。

2. 用語を分解する

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

文字を表す枠組み、文字をバイト列にする規則、行区切りや先頭の目印を分けると、用語を混同しにくくなります。

用語 何を指すか 例 よくある混同
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_JIS と CP932 をどう考えるか

現場では、日本語 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 ANSI、Unicode、UTF-8N という言葉の罠

ファイルの保存メニューにある名前が、そのまま厳密な形式名とは限りません。特に次の三つは、ツールが何を意味しているかまで確認してください。

表示される名前 その名前が指すことのある形式 混同しないこと
ANSI 多くの場合、そのマシンのアクティブコードページ (ACP) ASCII ではなく、環境によってコードページが変わる
Unicode 一部のエディタやツールでは UTF-16LE Unicode 全体の意味と、保存メニューの意味は同じとは限らない。UTF-8 の指定とも限らない
UTF-8N 日本語圏のエディタで見かける UTF-8 no BOM の区別 文字コードの正式名称ではなく、BOM なしを示す UI ラベル

同じ言葉でも、ツールごとに指す形式がずれることがあります。 「ANSI で保存した」「Unicode にした」という報告だけで判断せず、2.2 節のように具体的な文字コード名で記録すると、書く側と読む側の会話がそろいます。

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

バイト順の目印と、UTF-8 のシグネチャを分ける

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

UTF-16 は 2 バイト、UTF-32 は 4 バイトの単位で符号化します。その単位を「下位バイトから並べるか (リトルエンディアン)」「上位バイトから並べるか (ビッグエンディアン)」を、読む側とそろえる必要があります。BOM を使う場合は、その並び順で以降のバイト順を示します。なお、UTF-16 の 1 文字が常に 2 バイトという意味ではありません。符号点によっては 2 単位を使います (参考資料 7)。

先頭のバイト列 意味
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 は、読む側との相性で決める

UTF-8 の BOM には、次の利点と注意点があります。

  • BOM を付ける利点: 読む側が文字コードの推測に失敗しにくくなります。特に Windows PowerShell 5.1 は、BOM のないスクリプトファイルをアクティブコードページとして読みます。非 ASCII 文字を含む UTF-8 スクリプトでは、その前提が合わず文字化けすることがあるため、UTF-8 with BOM が必要になります (参考資料 2)。
  • 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: 分かれ目は「開き直したか、保存したか」の一手だけ。調査では必ずここを先に確認する

図2は、誤読した内容の再保存で元の情報が失われる場合を示しています。復元できるかは実際に残っているバイト列によるため、「保存した」という事実だけで決めつけるのではなく、元のバイト列が残っているかを確認します。

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

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

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

3.1 節は「読む前提」のずれでした。もう一つ区別したいのが、保存先の文字コードで、その文字を表現できるかという問題です。Unicode 文字列を CP932 のような、表せる文字の範囲が限られたコードページへ変換するときに起きます。

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

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

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

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

4. 改行文字の違いとは

4.1 CRLF / LF / CR

CR は carriage return、LF は line feed の略です。Windows の従来のテキストファイルでは二つを組み合わせた CRLF、Linux / Unix 系や現在の macOS では LF が一般的です。CR 単独は旧 Mac 系などの古いデータで見かけます。

次のバイト列は、UTF-8 や CP932 のような ASCII 互換の文字コードでの表現です。改行の選び方は文字コードとは別ですが、保存されるバイト列は文字コードにも依存します。 たとえば UTF-16LE の CRLF は 0D 00 0A 00 になります。

改行 バイト列 主な文脈
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 上で \n が CRLF に変換されることがあります。

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

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

このため、「自分は 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 ファイルの中身、ファイル名、コンソール、ソースファイルは別レイヤ

同じ「文字コード」の話でも、確認する対象は一つではありません。どの層で問題が起きているかを分けます。

確認する対象 切り分けること
ファイル名 / パス 名前が正しく見えることと、ファイル内容を正しく読めることは別
ファイルの中身 保存されたバイト列を、どの文字コードで読むか
コンソールへの表示 コンソール側のコードページや表示の前提が合っているか
ソースコードファイル自体 ソースを読む前提と、実行時の出力形式は別
実行時の文字列形式 メモリ上の文字列と、ファイルへ書くバイト列を区別する
クリップボードや GUI 部品上の表示 画面で見えている文字と、保存・通信時の形式を区別する

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

chcp 65001 は、既存ファイルを UTF-8 に変換する操作ではありません。 基本的にはコンソール側の前提に効くものであり、ファイル内のバイト列とは切り分けて考えます。

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

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

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

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

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

  • BOM はあるか、ないか
  • 改行は CRLF か LF か

たとえば、同じ 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 を第一候補にしつつ、読む相手を先に確認して、BOM と改行を決めます。 「UTF-8 に統一」で検討を止めないことが重要です。

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

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

たとえば、クロスプラットフォーム前提のソースコードや設定ファイルなら、UTF-8 no BOM + LF が第一候補になりやすいです。 一方で、Windows の古いツールや既存運用へ合わせる必要があるなら、UTF-8 with BOM や CP932 + 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 確認するには - ツール別の見どころ

ツールの操作でも、現在の状態を見ること、別の前提で開き直すこと、変換して保存することを区別します。まず、よく使う三つの確認場所を押さえてください。

ツール 今の文字コードを見る場所 変える場所
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 あり)、utf16le、windows1252 などです。言語ごとに分けることもできます。

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

この例は PowerShell 言語として扱われるファイルの既定を BOM ありにする設定です。Windows PowerShell 5.1 用と PowerShell 7 用を自動で判別する設定ではないため、5.1 用の作業範囲に適用するなど、2.4 節の「誰が読むか」に合わせて使います。

メモ帳

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

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

PowerShell

最初に PowerShell のバージョンと、読み書きに使ったコマンドを確認します。 同じ utf8 という指定でも、バージョンによって BOM の扱いが違います (参考資料 2)。

比べること Windows PowerShell 5.1 PowerShell 6 以降 (7 系を含む)
テキスト出力の既定 コマンドレットごとに異なる 原則として utf8NoBOM
-Encoding utf8 の意味 UTF-8 with BOM UTF-8 no BOM
BOM の有無を指定する名前 utf8 は BOM あり utf8BOM / utf8NoBOM で指定できる
  • PowerShell 6 以降 (PowerShell 7 系): すべてのテキスト出力の既定が utf8NoBOM、つまり UTF-8 の BOM なし です。
  • Windows PowerShell 5.1: 既定がコマンドレットごとに揃っていません。

5.1 の書き出しと読み込みを、別々に確認する

Windows PowerShell 5.1 の主な書き出しコマンドは次のとおりです。

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

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

BOM の確認は、表示名ではなく先頭バイトを見る

次の例は、ファイルの先頭 3 バイトを確認するものです。文字コードを自動確定するコマンドではありません。

# 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

2.4 節の候補では、EF BB BF は UTF-8、FF FE は UTF-16LE、FE FF は UTF-16BE の BOM です。ただし UTF-32LE の BOM も FF FE 00 00 で始まるため、先頭 3 バイトだけでは UTF-16LE と UTF-32LE を確定できません。 UTF-32BE には 00 00 FE FF もあります。UTF-32 まで候補に含める場合は少なくとも 4 バイトを確認し、書いた側の仕様や後続のバイト列も照合します (参考資料 7)。

また、BOM が見当たらないことだけでは、UTF-8 と CP932 などのどれで書かれたかは確定しません。BOM の有無の確認と、文字コードの判定は別の作業です。

既定値の設定と、外部プログラムへの受け渡しを分ける

既定を明示的に固定したい場合は、$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 問で確認した事実を埋めます。ただし、実際の操作では 5 問目の「すでに保存したか」を先に確認し、原因が分かる前の上書き保存を避けてください。

問い 確認すること 関連する説明
1. 今このファイルのバイト列は何か UTF-8、UTF-8 with BOM、CP932、UTF-16LE などの候補を、実際のバイト列と書いた側の仕様で確かめる 2.1 節以降の用語とバイト列、7.7 節の確認方法
2. 最初に誰が、どの前提で書いたか エディタ、レガシーアプリ、Excel のエクスポート、シェル / スクリプト、バッチ / ミドルウェアの設定と既定値を見る 5 章のツールと前提、7.3 節の受け渡し仕様
3. 今誰が、どの前提で読んでいるか エディタの自動判定、コンソールのコードページ、ライブラリの既定の文字コード、インポート側の仕様を分ける 5.4 節の層の切り分け、7.7 節のツール別確認
4. BOM と改行は何か BOM の有無と種類、CRLF / LF を、文字コードとは別に確認する 2.4 節の BOM、4 章の改行
5. 誤読した内容が、すでに保存されたか まだ表示だけの問題なのか、再保存で元のバイト列が失われたのかを確認する 3.2 節の表示崩れとデータ破損

この 5 問を埋めると、「読む前提を直せばよいのか」「保存側や受け渡しの仕様を直す必要があるのか」「元の情報が失われているのか」を分けて考えられます。

9. まとめ

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

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

  • 文字化けは、同じバイト列を別の文字コードとして読んだ結果
  • 改行問題は、文字コードとは別軸の話
  • Shift_JIS、CP932、ANSI、Unicode という言葉はそのまま信用しすぎない
  • 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 ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る