C#の文字コード入門|UTF-8・Shift_JIS変換と文字化け対策をコード例で解説

はじめに

C#で日本語を含むファイル、CSV、Web API、外部システム連携を扱うときに避けて通れないのが「文字コード」です。

たとえば、次のような経験はないでしょうか。

  • CSVを読み込んだら日本語が文字化けした

  • UTF-8で保存したはずのファイルをExcelで開くと文字化けする

  • Shift_JISのファイルを.NETで読み込もうとして例外が出る

  • コンソールに日本語を出力すると「???」や謎の記号になる

  • 外部コマンドの標準出力だけ文字化けする

C#では、文字列そのものはstringとして扱えますが、ファイルや通信、CSV、標準出力など外部との入出力では必ず「文字列」と「バイト列」の変換が発生します。この変換に使うルールが文字コードです。

この記事では、C#の文字コードについて、UTF-8、Shift_JIS、UTF-16の基礎から、Encodingクラスの使い方、UTF-8とShift_JISの相互変換、文字化け対策、よくあるエラーの解決策まで、コード例付きで解説します。

1. C#の文字コードとは?まず押さえるべき基礎知識

1-1. 文字コード・エンコード・デコードの違い

文字コードを理解するうえで、まず次の3つを区別しておきましょう。

文字コードとは、文字をコンピューター上で表現するためのルールです。代表的なものに、UTF-8、Shift_JIS、UTF-16、ASCIIなどがあります。

エンコードとは、文字列をバイト配列に変換する処理です。

C#
string text = "こんにちは";
byte[] bytes = Encoding.UTF8.GetBytes(text);

デコードとは、バイト配列を文字列に戻す処理です。

C#
string decoded = Encoding.UTF8.GetString(bytes);

C#では、文字列をファイルに保存したり、ネットワークで送信したりするときにエンコードが行われます。逆に、ファイルや通信から受け取ったバイト列をstringとして扱うときにはデコードが行われます。

Microsoftの.NETドキュメントでも、EncodingはUnicode文字列をバイト列へ変換し、逆にバイト列をUnicode文字列へ戻すためのクラスとして説明されています。Microsoft Learn

1-2. C#のstringは内部的にUnicodeとして扱われる

C#のstringは、UTF-8やShift_JISそのものではありません。.NETのstring内のテキストはUTF-16として扱われ、charは16ビットのコード単位を表します。Microsoft Learn

つまり、次のように考えると理解しやすくなります。

C#のstring
↓ Encoding.UTF8.GetBytes()
UTF-8のバイト配列

C#のstring
↓ Encoding.GetEncoding("shift_jis").GetBytes()
Shift_JISのバイト配列

stringはあくまでアプリケーション内部で扱う文字列です。UTF-8やShift_JISを意識するのは、主にファイル保存、ファイル読み込み、通信、標準入出力、外部システム連携などの場面です。

1-3. UTF-8・Shift_JIS・UTF-16の違い

C#でよく出てくる文字コードには、主に次のような違いがあります。

文字コード特徴よく使われる場面
UTF-8世界的に広く使われる可変長文字コード。英数字は1バイト、日本語は主に3バイトWeb、API、JSON、HTML、現代的なテキストファイル
Shift_JIS日本語Windows環境で古くから使われる文字コード古い業務システム、Excel向けCSV、レガシー連携
UTF-16.NETのstring内部表現で使われるC#内部、Windows API、メモリ上の文字列処理

新規開発では基本的にUTF-8を選ぶのが無難です。一方で、日本の業務システムや古いCSV連携ではShift_JISが指定されることも多いため、C#でShift_JISを扱う方法も理解しておく必要があります。

1-4. 文字コードを間違えると文字化けが起きる理由

文字化けは、エンコード時とデコード時の文字コードが一致していないときに発生します。

たとえば、Shift_JISで保存されたファイルをUTF-8として読み込むと、バイト列の解釈がずれてしまいます。

Shift_JISで保存されたバイト列
↓ UTF-8として読み込む
文字化け

逆に、UTF-8で保存されたファイルをShift_JISとして読み込んでも文字化けします。

文字コードの問題は「文字列が壊れた」のではなく、「バイト列を間違ったルールで解釈した」と考えると原因を追いやすくなります。

2. C#で文字コードを扱う基本|Encodingクラスの使い方

2-1. System.Text.Encodingとは

C#で文字コードを扱うときは、System.Text.Encodingクラスを使います。

C#
using System.Text;

Encodingクラスには、UTF-8、UTF-16、ASCIIなどを扱うためのプロパティや、任意の文字コードを取得するためのGetEncodingメソッドが用意されています。

代表的な使い方は次のとおりです。

C#
Encoding utf8 = Encoding.UTF8;
Encoding unicode = Encoding.Unicode; // UTF-16 Little Endian
Encoding ascii = Encoding.ASCII;

Encodingクラスは、文字列とバイト配列の変換を行う中心的なクラスです。

2-2. Encoding.UTF8でUTF-8を扱う方法

UTF-8を扱う場合は、基本的にEncoding.UTF8を使います。

C#
using System.Text;

string text = "こんにちは";
Encoding encoding = Encoding.UTF8;

byte[] bytes = encoding.GetBytes(text);
string result = encoding.GetString(bytes);

Console.WriteLine(result);

Encoding.UTF8は、C#でUTF-8の文字列変換を行うときに最もよく使う指定です。

ただし、BOMの有無を明示したい場合は、new UTF8Encoding(false)new UTF8Encoding(true)を使うとより意図が明確になります。

C#
// BOMなしUTF-8
Encoding utf8WithoutBom = new UTF8Encoding(false);

// BOM付きUTF-8
Encoding utf8WithBom = new UTF8Encoding(true);

UTF-8のBOMは必須ではなく、Unicode標準でもUTF-8ストリームにBOMは必要とされていません。Microsoft Learn

2-3. Encoding.GetEncodingで任意の文字コードを取得する方法

UTF-8以外の文字コードを使う場合は、Encoding.GetEncodingを使います。

C#
Encoding utf8 = Encoding.GetEncoding("utf-8");
Encoding sjis = Encoding.GetEncoding("shift_jis");

コードページ番号で指定することもできます。

C#
Encoding sjis = Encoding.GetEncoding(932);

Shift_JISを扱う場合、.NET Frameworkではそのまま使えることが多いですが、.NET Core.NET 5以降では後述するEncoding.RegisterProviderが必要になる場合があります。

2-4. GetBytesとGetStringで文字列とバイト配列を変換する方法

Encodingで最もよく使うメソッドは、GetBytesGetStringです。

GetBytesは、文字列をバイト配列へ変換します。

C#
string text = "C# 文字コード";
byte[] bytes = Encoding.UTF8.GetBytes(text);

GetStringは、バイト配列を文字列へ変換します。

C#
string result = Encoding.UTF8.GetString(bytes);

重要なのは、GetBytesGetStringで同じ文字コードを使うことです。

C#
string text = "こんにちは";

// UTF-8でエンコード
byte[] bytes = Encoding.UTF8.GetBytes(text);

// UTF-8でデコード
string decoded = Encoding.UTF8.GetString(bytes);

Console.WriteLine(decoded);

次のように、UTF-8でエンコードしたバイト列をShift_JISとしてデコードすると文字化けの原因になります。

C#
string text = "こんにちは";

byte[] utf8Bytes = Encoding.UTF8.GetBytes(text);

// 誤り:UTF-8のバイト列をShift_JISとして読む
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
string mojibake = Encoding.GetEncoding("shift_jis").GetString(utf8Bytes);

Console.WriteLine(mojibake);

2-5. Encoding.Defaultを安易に使わないほうがよい理由

Encoding.Defaultは便利そうに見えますが、安易に使わないほうが安全です。

理由は、実行環境によって意味が変わるためです。.NET Frameworkではシステムのアクティブなコードページに対応するエンコードを返しますが、.NET Core以降では常にUTF-8を返します。Microsoft Learn

C#
Encoding encoding = Encoding.Default;

このコードは、環境によって結果が変わる可能性があります。そのため、ファイル入出力や外部連携では次のように明示的に指定することをおすすめします。

C#
Encoding encoding = Encoding.UTF8;
// または
Encoding encoding = Encoding.GetEncoding("shift_jis");

文字化けを防ぐ基本は、「推測に頼らず、文字コードを明示すること」です。

3. C#でUTF-8を扱う方法

3-1. UTF-8で文字列をバイト配列に変換するコード例

C#で文字列をUTF-8のバイト配列に変換するには、Encoding.UTF8.GetBytesを使います。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
string text = "こんにちは、C#";

byte[] utf8Bytes = Encoding.UTF8.GetBytes(text);

Console.WriteLine(BitConverter.ToString(utf8Bytes));
}
}

BitConverter.ToStringを使うと、バイト配列を16進数で確認できます。文字コードの調査をするときに便利です。

3-2. UTF-8のバイト配列を文字列に戻すコード例

UTF-8のバイト配列を文字列に戻すには、Encoding.UTF8.GetStringを使います。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
byte[] utf8Bytes = Encoding.UTF8.GetBytes("日本語テキスト");

string text = Encoding.UTF8.GetString(utf8Bytes);

Console.WriteLine(text);
}
}

エンコードとデコードの両方でEncoding.UTF8を使っているため、正しく元の文字列に戻ります。

3-3. UTF-8でテキストファイルを読み込む方法

UTF-8のテキストファイルを読み込むには、File.ReadAllTextEncoding.UTF8を指定します。

C#
using System;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "sample.txt";

string text = File.ReadAllText(path, Encoding.UTF8);

Console.WriteLine(text);
}
}

大きなファイルを1行ずつ読み込む場合は、StreamReaderを使います。

C#
using System;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "sample.txt";

using StreamReader reader = new StreamReader(path, Encoding.UTF8);

string? line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
}

文字化けを避けるため、読み込むファイルの文字コードがUTF-8であることを確認したうえで指定しましょう。

3-4. UTF-8でテキストファイルを書き込む方法

UTF-8でファイルを書き込むには、File.WriteAllTextEncoding.UTF8を指定します。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "output.txt";
string text = "UTF-8で保存します。";

File.WriteAllText(path, text, Encoding.UTF8);
}
}

BOMなしUTF-8で保存したい場合は、UTF8Encodingを明示します。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "output.txt";
string text = "BOMなしUTF-8で保存します。";

Encoding utf8WithoutBom = new UTF8Encoding(false);

File.WriteAllText(path, text, utf8WithoutBom);
}
}

BOM付きUTF-8で保存したい場合は、次のようにします。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "output_with_bom.txt";
string text = "BOM付きUTF-8で保存します。";

Encoding utf8WithBom = new UTF8Encoding(true);

File.WriteAllText(path, text, utf8WithBom);
}
}

3-5. BOM付きUTF-8とBOMなしUTF-8の違い

BOMとは、ファイルの先頭に付く数バイトの識別情報です。UTF-8のBOMは、16進数で次の3バイトです。

EF BB BF

BOM付きUTF-8は、一部のアプリケーションが文字コードを判定しやすくなるメリットがあります。一方で、BOMを想定していないシステムでは、ファイル先頭に余計な文字が入ったように扱われることがあります。

たとえば、CSVや設定ファイルの先頭項目にBOMが混ざり、次のような問題が起きることがあります。

"Name" ではなく "\uFEFFName" として扱われる

新規開発ではBOMなしUTF-8を基本にしつつ、Excelや外部システムの仕様に合わせてBOM付きUTF-8を選ぶとよいでしょう。

4. C#でShift_JISを扱う方法

4-1. Shift_JISとは?日本語環境で使われる理由

Shift_JISは、日本語Windows環境で長く使われてきた文字コードです。現在ではWebやAPIではUTF-8が主流ですが、次のような場面ではShift_JISが残っています。

  • 古い業務システムとの連携

  • Excelで開くことを前提にしたCSV

  • Windows向けのレガシーアプリケーション

  • 金融、物流、販売管理などの既存システム

  • 仕様書で「文字コード:Shift_JIS」と指定されているデータ連携

C#で新規開発する場合はUTF-8を基本にするべきですが、現場ではShift_JISの読み書きが必要になることも多いため、扱い方を覚えておくと実務で役立ちます。

4-2. Shift_JISを使う前に必要なEncoding.RegisterProvider

.NET Coreや.NET 5以降でShift_JISを使う場合、Encoding.GetEncoding("shift_jis")を呼び出す前に、コードページエンコーディングプロバイダーを登録する必要があります。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Microsoftのドキュメントでも、RegisterProviderを使うことで、標準では利用できないエンコーディングをEncoding.GetEncodingから取得できるようになると説明されています。Microsoft Learn

また、プロジェクトによってはNuGetパッケージSystem.Text.Encoding.CodePagesの追加が必要です。

Bash
dotnet add package System.Text.Encoding.CodePages

そのうえで、次のようにShift_JISを取得します。

C#
using System.Text;

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

4-3. .NET Core・.NET 5以降でShift_JISを有効化するコード例

.NET Core、.NET 5、.NET 6、.NET 7、.NET 8以降でShift_JISを使う基本コードは次のとおりです。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "こんにちは";
byte[] bytes = sjis.GetBytes(text);

Console.WriteLine(BitConverter.ToString(bytes));
}
}

コードページ番号で指定する場合は、次のように書けます。

C#
Encoding sjis = Encoding.GetEncoding(932);

実務では、"shift_jis"よりも932を指定しているコードもよく見かけます。

4-4. Shift_JISで文字列をバイト配列に変換する方法

Shift_JISで文字列をバイト配列に変換するには、Shift_JISのEncodingを取得してからGetBytesを使います。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "株式会社サンプル";
byte[] sjisBytes = sjis.GetBytes(text);

Console.WriteLine(BitConverter.ToString(sjisBytes));
}
}

ファイル送信や外部システム連携で「Shift_JISのバイト列」が必要な場合は、このようにGetBytesで変換します。

4-5. Shift_JISのバイト配列を文字列に戻す方法

Shift_JISのバイト配列をC#の文字列に戻すには、同じShift_JISのEncodingGetStringを使います。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string original = "日本語";
byte[] sjisBytes = sjis.GetBytes(original);

string decoded = sjis.GetString(sjisBytes);

Console.WriteLine(decoded);
}
}

Shift_JISで作られたバイト列をUTF-8として読んではいけません。必ず元の文字コードに合わせてデコードしてください。

4-6. 「'shift_jis' is not a supported encoding name」エラーの原因と対処法

.NET Coreや.NET 5以降で次のようなエラーが出ることがあります。

'shift_jis' is not a supported encoding name.

原因は、Shift_JISなどのコードページエンコーディングが有効化されていないことです。

対処法は、System.Text.Encoding.CodePagesパッケージを追加し、Encoding.RegisterProviderを呼び出すことです。

Bash
dotnet add package System.Text.Encoding.CodePages
C#
using System.Text;

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

アプリケーション起動時に1回登録しておけば、その後はEncoding.GetEncoding("shift_jis")を使えるようになります。

5. C#でUTF-8とShift_JISを相互変換する方法

5-1. UTF-8からShift_JISへ変換する基本コード

C#のstringを経由してUTF-8からShift_JISへ変換する基本コードです。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding utf8 = Encoding.UTF8;
Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "UTF-8からShift_JISへ変換";

byte[] utf8Bytes = utf8.GetBytes(text);

// UTF-8のバイト列を文字列に戻す
string decodedText = utf8.GetString(utf8Bytes);

// Shift_JISのバイト列に変換
byte[] sjisBytes = sjis.GetBytes(decodedText);

Console.WriteLine(BitConverter.ToString(sjisBytes));
}
}

すでにC#のstringとして文字列を持っている場合は、単にShift_JISでGetBytesすれば十分です。

C#
byte[] sjisBytes = sjis.GetBytes(text);

5-2. Shift_JISからUTF-8へ変換する基本コード

Shift_JISのバイト配列をUTF-8のバイト配列に変換するには、まずShift_JISとしてデコードし、その後UTF-8でエンコードします。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");
Encoding utf8 = Encoding.UTF8;

byte[] sjisBytes = sjis.GetBytes("Shift_JISからUTF-8へ変換");

// Shift_JISのバイト列を文字列へ
string text = sjis.GetString(sjisBytes);

// UTF-8のバイト列へ
byte[] utf8Bytes = utf8.GetBytes(text);

Console.WriteLine(BitConverter.ToString(utf8Bytes));
}
}

ポイントは、元のバイト列がどの文字コードで作られたかを正しく指定することです。

5-3. Encoding.Convertを使った文字コード変換

Encoding.Convertを使うと、ある文字コードのバイト配列を別の文字コードのバイト配列へ変換できます。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding utf8 = Encoding.UTF8;
Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "文字コード変換";
byte[] utf8Bytes = utf8.GetBytes(text);

byte[] sjisBytes = Encoding.Convert(utf8, sjis, utf8Bytes);

Console.WriteLine(BitConverter.ToString(sjisBytes));
}
}

Encoding.Convertは「入力バイト列の文字コード」と「出力したい文字コード」が明確な場合に便利です。

ただし、C#のstringをすでに持っているなら、次のように書くほうがシンプルです。

C#
byte[] sjisBytes = sjis.GetBytes(text);

5-4. ファイルをUTF-8からShift_JISへ変換するコード例

UTF-8のテキストファイルを読み込み、Shift_JISで別ファイルに保存する例です。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding utf8 = Encoding.UTF8;
Encoding sjis = Encoding.GetEncoding("shift_jis");

string inputPath = "input_utf8.txt";
string outputPath = "output_sjis.txt";

string text = File.ReadAllText(inputPath, utf8);

File.WriteAllText(outputPath, text, sjis);
}
}

この方法では、一度C#のstringとして読み込み、保存時にShift_JISへエンコードしています。

5-5. ファイルをShift_JISからUTF-8へ変換するコード例

Shift_JISのファイルを読み込み、UTF-8で保存するコード例です。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");
Encoding utf8WithoutBom = new UTF8Encoding(false);

string inputPath = "input_sjis.txt";
string outputPath = "output_utf8.txt";

string text = File.ReadAllText(inputPath, sjis);

File.WriteAllText(outputPath, text, utf8WithoutBom);
}
}

BOM付きUTF-8で保存したい場合は、次のように変更します。

C#
Encoding utf8WithBom = new UTF8Encoding(true);
File.WriteAllText(outputPath, text, utf8WithBom);

5-6. 変換できない文字がある場合の注意点

UTF-8は多くの文字を表現できますが、Shift_JISでは表現できない文字があります。たとえば、一部の絵文字、特殊記号、外字、サロゲートペアを含む文字などはShift_JISに変換できない場合があります。

その場合、標準の変換では?に置き換わることがあります。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "絵文字😊";
byte[] bytes = sjis.GetBytes(text);

string result = sjis.GetString(bytes);

Console.WriteLine(result);

変換できない文字を検出したい場合は、例外を投げるフォールバックを指定します。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjisStrict = Encoding.GetEncoding(
"shift_jis",
new EncoderExceptionFallback(),
new DecoderExceptionFallback()
);

string text = "絵文字😊";

try
{
byte[] bytes = sjisStrict.GetBytes(text);
}
catch (EncoderFallbackException ex)
{
Console.WriteLine("Shift_JISに変換できない文字があります。");
Console.WriteLine(ex.Message);
}
}
}

外部システムにShift_JISで送る場合は、送信前に変換不可文字がないかチェックすることが重要です。

6. C#の文字化け対策

6-1. 文字化けが発生する主な原因

C#で文字化けが発生する主な原因は次のとおりです。

  • 読み込み時の文字コード指定が間違っている

  • 書き込み時の文字コード指定が間違っている

  • UTF-8とShift_JISを混同している

  • BOMあり・BOMなしの違いを考慮していない

  • コンソールやターミナル側の文字コードが合っていない

  • 外部コマンドの標準出力の文字コードが合っていない

  • HTTPレスポンスのcharsetを無視している

  • CSVをExcelで開く前提なのにUTF-8 BOMなしで出力している

  • Shift_JISに存在しない文字を変換している

文字化け調査では、まず「どの時点で、どの文字コードのバイト列になっているか」を確認することが大切です。

6-2. 読み込み時と書き込み時の文字コードを一致させる

最も基本的な対策は、読み込み時と書き込み時の文字コードを一致させることです。

UTF-8のファイルはUTF-8で読みます。

C#
string text = File.ReadAllText("utf8.txt", Encoding.UTF8);

Shift_JISのファイルはShift_JISで読みます。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = File.ReadAllText("sjis.txt", sjis);

書き込み時も同様です。

C#
File.WriteAllText("output_utf8.txt", text, Encoding.UTF8);
File.WriteAllText("output_sjis.txt", text, sjis);

文字コードが仕様書で決まっている場合は、必ずその指定に従いましょう。

6-3. Web・API・CSV・テキストファイルで起きやすい文字化け

WebやAPIでは、現在はUTF-8が主流です。JSONも通常はUTF-8で扱うことが多いです。

一方、CSVでは状況が分かれます。

  • システム連携用CSV:仕様書で指定された文字コードに従う

  • Excelで開くCSV:Shift_JISまたはBOM付きUTF-8が必要な場合がある

  • WebアプリからダウンロードするCSV:利用者の環境に合わせて検討する

テキストファイルでは、拡張子.txtだけでは文字コードは判断できません。ファイルの作成元、仕様書、BOM、実際のバイト列を確認する必要があります。

6-4. コンソール出力で日本語が文字化けする場合の対処法

コンソールに日本語を出力したときに文字化けする場合は、Console.OutputEncodingを設定します。

C#
using System;
using System.Text;

class Program
{
static void Main()
{
Console.OutputEncoding = Encoding.UTF8;

Console.WriteLine("こんにちは、C#");
}
}

Windowsの古いコマンドプロンプトでは、コンソール側のコードページも影響します。UTF-8に切り替える場合は、次のコマンドを使うことがあります。

cmd
chcp 65001

ただし、Windows Terminal、PowerShell、Visual Studioのデバッグコンソールなど、実行環境によって挙動が異なります。アプリ側のConsole.OutputEncodingと、表示側のターミナル設定の両方を確認しましょう。

入力側で文字化けする場合は、Console.InputEncodingも指定します。

C#
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;

6-5. StreamReader・StreamWriterで文字コードを明示する

StreamReaderStreamWriterを使う場合も、文字コードを明示するのが安全です。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
using StreamReader reader = new StreamReader("input.txt", Encoding.UTF8);
using StreamWriter writer = new StreamWriter("output.txt", false, Encoding.UTF8);

string? line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
}
}

Shift_JISの場合は次のようにします。

C#
using System.IO;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding sjis = Encoding.GetEncoding("shift_jis");

using StreamReader reader = new StreamReader("input_sjis.txt", sjis);
using StreamWriter writer = new StreamWriter("output_sjis.txt", false, sjis);

string? line;
while ((line = reader.ReadLine()) != null)
{
writer.WriteLine(line);
}
}
}

StreamReaderはBOMによるエンコーディング検出を行える場合がありますが、BOMがないファイルでは指定したエンコーディングが使われます。BOMだけに頼らず、仕様として文字コードを明示するのが確実です。Microsoft Learn

6-6. 文字コードを自動判定するときの注意点

文字コードの自動判定は便利に見えますが、完全ではありません。

特に、UTF-8 BOMなしとShift_JISは、短い日本語テキストでは誤判定されることがあります。英数字だけのファイルは、UTF-8でもShift_JISでも同じバイト列に見える場合があります。

自動判定を使う場合でも、次の優先順位で考えるのがおすすめです。

  1. 仕様書の文字コードを確認する

  2. HTTPヘッダーやメタ情報のcharsetを確認する

  3. BOMを確認する

  4. それでも不明な場合のみ自動判定を使う

  5. 判定結果をログに残す

  6. 誤判定時に手動指定できるようにする

文字コードは、できるだけ「推測」ではなく「仕様」として扱うべきです。

7. よく使う文字コード指定のコード例

7-1. UTF-8でCSVファイルを読み込む

UTF-8のCSVを読み込む基本例です。

C#
using System;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "data_utf8.csv";

using StreamReader reader = new StreamReader(path, Encoding.UTF8);

string? line;
while ((line = reader.ReadLine()) != null)
{
string[] columns = line.Split(',');

Console.WriteLine(string.Join(" | ", columns));
}
}
}

ただし、実務のCSVにはカンマを含む値やダブルクォートで囲まれた値が登場します。単純なSplit(',')では正しく処理できない場合があるため、本格的なCSV処理ではCSVパーサーの利用も検討しましょう。

7-2. Shift_JISでCSVファイルを読み込む

Shift_JISのCSVを読み込む例です。

C#
using System;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string path = "data_sjis.csv";

using StreamReader reader = new StreamReader(path, sjis);

string? line;
while ((line = reader.ReadLine()) != null)
{
string[] columns = line.Split(',');

Console.WriteLine(string.Join(" | ", columns));
}
}
}

Excelや古い業務システムから出力されたCSVはShift_JISであることが多いため、文字化けする場合はUTF-8ではなくShift_JISで読み込んでみる価値があります。

7-3. UTF-8でCSVファイルを書き出す

UTF-8でCSVを書き出す例です。

C#
using System.Collections.Generic;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
string path = "output_utf8.csv";

var lines = new List<string>
{
"Id,Name,Address",
"1,山田太郎,東京都",
"2,佐藤花子,大阪府"
};

File.WriteAllLines(path, lines, new UTF8Encoding(false));
}
}

BOMなしUTF-8で出力したい場合は、new UTF8Encoding(false)を指定します。

Excelで開く前提の場合は、BOM付きUTF-8やShift_JISのほうが適している場合があります。

7-4. Shift_JISでCSVファイルを書き出す

Shift_JISでCSVを書き出す例です。

C#
using System.Collections.Generic;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string path = "output_sjis.csv";

var lines = new List<string>
{
"Id,Name,Address",
"1,山田太郎,東京都",
"2,佐藤花子,大阪府"
};

File.WriteAllLines(path, lines, sjis);
}
}

Excelで開くことを想定したCSVでは、Shift_JISが求められることがあります。ただし、Shift_JISでは表現できない文字があるため、絵文字や特殊記号を含むデータには注意が必要です。

7-5. Webレスポンスの文字コードを指定して読み込む

HTTPレスポンスを文字コード指定で読み込む例です。

C#
using System;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program
{
static async Task Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

using HttpClient client = new HttpClient();

using HttpResponseMessage response =
await client.GetAsync("https://example.com/data.txt");

response.EnsureSuccessStatusCode();

string? charset = response.Content.Headers.ContentType?.CharSet;

Encoding encoding = !string.IsNullOrWhiteSpace(charset)
? Encoding.GetEncoding(charset)
: Encoding.UTF8;

await using Stream stream = await response.Content.ReadAsStreamAsync();
using StreamReader reader = new StreamReader(stream, encoding);

string text = await reader.ReadToEndAsync();

Console.WriteLine(text);
}
}

Webレスポンスでは、Content-Typeヘッダーに次のような文字コード情報が含まれることがあります。

http
Content-Type: text/html; charset=shift_jis

charsetが指定されている場合は、それに従って読み込むのが基本です。

7-6. 外部コマンドの標準出力で文字化けする場合の対応

C#から外部コマンドを実行し、標準出力を読み取るときに文字化けする場合は、StandardOutputEncodingを指定します。

C#
using System;
using System.Diagnostics;
using System.Text;

class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

var startInfo = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = "/c echo こんにちは",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
StandardOutputEncoding = Encoding.GetEncoding("shift_jis")
};

using Process process = Process.Start(startInfo)!;

string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();

Console.WriteLine(output);
}
}

外部コマンドがUTF-8で出力する場合は、次のようにします。

C#
StandardOutputEncoding = Encoding.UTF8

標準エラー出力も読み取る場合は、StandardErrorEncodingも指定します。

C#
var startInfo = new ProcessStartInfo
{
FileName = "mytool.exe",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
StandardOutputEncoding = Encoding.UTF8,
StandardErrorEncoding = Encoding.UTF8
};

8. C#の文字コードでよくあるエラーと解決策

8-1. Encoding.GetEncoding("shift_jis")で例外が出る

.NET Core.NET 5以降で、次のコードが例外になることがあります。

C#
Encoding sjis = Encoding.GetEncoding("shift_jis");

原因は、Shift_JISなどのコードページが標準で有効になっていないことです。

解決策は、System.Text.Encoding.CodePagesを追加して、Encoding.RegisterProviderを呼び出すことです。

Bash
dotnet add package System.Text.Encoding.CodePages
C#
using System.Text;

Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

.NET 5以降では、登録されたエンコーディングプロバイダーによって追加のエンコーディングを取得できるようになります。Microsoft Learn

8-2. 日本語の一部だけが「?」になる

日本語の一部だけが?になる場合、変換先の文字コードで表現できない文字が含まれている可能性があります。

特にShift_JISでは、絵文字や一部の特殊文字を表現できません。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = "テスト😊";
byte[] bytes = sjis.GetBytes(text);

string result = sjis.GetString(bytes);

Console.WriteLine(result);

このような問題を検出したい場合は、EncoderExceptionFallbackを使います。

C#
Encoding sjisStrict = Encoding.GetEncoding(
"shift_jis",
new EncoderExceptionFallback(),
new DecoderExceptionFallback()
);

変換できない文字を?に置き換えてよいのか、エラーにして処理を止めるべきなのかは、システム要件に合わせて決めましょう。

8-3. CSVをExcelで開くと文字化けする

UTF-8のCSVをExcelで直接開くと、環境によって文字化けすることがあります。

対策としては、主に次の方法があります。

  • BOM付きUTF-8で出力する

  • Shift_JISで出力する

  • Excelの「データの取得」機能からUTF-8を指定して開く

  • 利用者向けに開き方を案内する

BOM付きUTF-8で出力する例です。

C#
using System.Collections.Generic;
using System.IO;
using System.Text;

class Program
{
static void Main()
{
var lines = new List<string>
{
"Id,Name",
"1,山田太郎"
};

Encoding utf8WithBom = new UTF8Encoding(true);

File.WriteAllLines("excel_utf8_bom.csv", lines, utf8WithBom);
}
}

Shift_JISで出力する例です。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis = Encoding.GetEncoding("shift_jis");

File.WriteAllLines("excel_sjis.csv", lines, sjis);

Excelでの利用を前提にする場合は、利用者の環境や要件に合わせて選びましょう。

8-4. UTF-8のはずなのに日本語が崩れる

「UTF-8のはずなのに文字化けする」場合は、次の点を確認します。

  • 本当にファイルがUTF-8か

  • BOM付きかBOMなしか

  • 読み込み側でUTF-8を指定しているか

  • 途中でShift_JISとして読み書きしていないか

  • HTTPヘッダーのcharsetが間違っていないか

  • ファイル作成元のアプリが別の文字コードで保存していないか

  • ログ出力やコンソール表示の段階で文字化けしていないか

特に注意したいのは、「ファイル自体は正しいが、表示する環境が文字コードに対応していない」ケースです。

たとえば、UTF-8の文字列を正しく読み込めていても、コンソールの出力設定が合っていなければ表示時に文字化けします。

8-5. 改行コードと文字コードを混同しない

文字コードと改行コードは別の概念です。

文字コードは、文字をバイト列に変換するルールです。

UTF-8
Shift_JIS
UTF-16

改行コードは、行の終わりを表す文字の並びです。

CRLF: \r\n
LF: \n
CR: \r

WindowsではCRLF、LinuxやmacOSではLFがよく使われます。

C#で改行コードを変換する例です。

C#
string text = File.ReadAllText("input.txt", Encoding.UTF8);

// LFに統一
text = text.Replace("\r\n", "\n").Replace("\r", "\n");

File.WriteAllText("output.txt", text, Encoding.UTF8);

文字化けしている場合は文字コードを確認し、行末が崩れる場合は改行コードを確認しましょう。

9. C#で文字コードを扱うときのベストプラクティス

9-1. 新規開発ではUTF-8を基本にする

新規開発では、基本的にUTF-8を選ぶのがおすすめです。

UTF-8はWeb、API、JSON、HTML、各種クラウドサービス、Linux環境などで広く使われています。多言語対応にも向いており、現代的なシステムでは標準的な選択肢です。

C#でUTF-8を明示する場合は、次のように書きます。

C#
Encoding encoding = Encoding.UTF8;

BOMなしを明示したい場合は、次のようにします。

C#
Encoding encoding = new UTF8Encoding(false);

9-2. 外部システム連携では仕様書の文字コードを確認する

外部システムと連携する場合は、必ず仕様書の文字コードを確認してください。

確認すべき項目は次のとおりです。

  • ファイルの文字コード

  • 改行コード

  • BOMの有無

  • CSVの区切り文字

  • 囲み文字

  • 使用可能な文字の範囲

  • 変換できない文字がある場合の扱い

  • HTTPヘッダーのcharset

  • 送信時と受信時で文字コードが同じか

「たぶんUTF-8」「おそらくShift_JIS」という推測で実装すると、後から文字化けやデータ欠損が発生しやすくなります。

9-3. ファイル入出力では必ずEncodingを明示する

ファイル入出力では、できるだけEncodingを明示しましょう。

C#
string text = File.ReadAllText("input.txt", Encoding.UTF8);
File.WriteAllText("output.txt", text, Encoding.UTF8);

Shift_JISの場合も同様です。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding sjis = Encoding.GetEncoding("shift_jis");

string text = File.ReadAllText("input.txt", sjis);
File.WriteAllText("output.txt", text, sjis);

Encoding.Defaultや環境依存の既定値に頼ると、開発環境では動いても本番環境で文字化けすることがあります。

9-4. Shift_JISが必要な場面と避けたほうがよい場面

Shift_JISが必要な場面はあります。

  • 連携先システムがShift_JIS指定

  • Excelで開くCSVが必要

  • 既存の業務システムがShift_JIS前提

  • 古いWindowsアプリと連携する

  • 仕様書でコードページ932が指定されている

一方で、次のような場面ではShift_JISを避けたほうがよいです。

  • 新規Web API

  • JSON

  • 多言語対応

  • 絵文字や特殊文字を扱うサービス

  • Linuxやクラウドを含むクロスプラットフォーム環境

  • 将来的な国際化を想定するシステム

Shift_JISは日本語レガシー連携では必要ですが、標準の保存形式としてはUTF-8を選ぶのが無難です。

9-5. 文字化け調査時に確認すべきチェックリスト

文字化けが発生したら、次の順番で確認すると原因を特定しやすくなります。

  1. 元ファイルの文字コードは何か

  2. 読み込み時に指定しているEncodingは何か

  3. 書き込み時に指定しているEncodingは何か

  4. UTF-8 BOMあり・BOMなしの違いは関係しているか

  5. Shift_JISに変換できない文字が含まれていないか

  6. コンソールやログ出力の文字コードは正しいか

  7. HTTPヘッダーのcharsetは正しいか

  8. Excelで開くことによる文字化けではないか

  9. 改行コードの問題と混同していないか

  10. 途中処理で別の文字コードとして読み書きしていないか

文字化けの原因は、読み込み、内部処理、書き込み、表示のどこかにあります。どの段階で崩れているかを切り分けることが重要です。

10. C#の文字コードに関するよくある質問

10-1. C#のstringの文字コードはUTF-8ですか?

いいえ。C#のstringはUTF-8ではありません。

.NETのstring内のテキストはUTF-16として扱われます。Encoding.UTF8.GetBytesを呼び出したときに、stringからUTF-8のバイト配列へ変換されます。Microsoft Learn

C#
string text = "こんにちは";

// stringをUTF-8のバイト列に変換
byte[] bytes = Encoding.UTF8.GetBytes(text);

つまり、UTF-8やShift_JISは、主に外部との入出力時に意識するものです。

10-2. UTF-8とShift_JISはどちらを使うべきですか?

新規開発では、基本的にUTF-8を使うのがおすすめです。

UTF-8は多言語対応に強く、Web、API、JSON、クラウド環境との相性も良いです。

ただし、次のような場合はShift_JISが必要になることがあります。

  • 連携先がShift_JIS指定

  • Excelで開くCSVを作成する

  • 古い業務システムと連携する

  • 仕様書でコードページ932が指定されている

迷った場合は、内部処理や保存形式はUTF-8、外部システムの仕様に合わせて必要な箇所だけShift_JISに変換する設計が扱いやすいです。

10-3. Shift_JISとcp932は同じですか?

厳密には同じではありません。

一般的にC#やWindows環境でEncoding.GetEncoding("shift_jis")Encoding.GetEncoding(932)を使う場合、Windowsのコードページ932、いわゆるCP932を指すことが多いです。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

Encoding sjis1 = Encoding.GetEncoding("shift_jis");
Encoding sjis2 = Encoding.GetEncoding(932);

実務では「Shift_JIS」と書かれていても、実際にはCP932を意味している仕様書が多くあります。ただし、厳密な文字集合や変換差異が問題になるシステムでは、仕様書で「Shift_JIS」「Windows-31J」「CP932」のどれを指しているか確認しましょう。

10-4. BOM付きUTF-8は必要ですか?

必ず必要ではありません。UTF-8ではBOMは必須ではなく、Unicode標準でもUTF-8ストリームにBOMは必要とされていません。Microsoft Learn

ただし、BOM付きUTF-8が役立つ場面もあります。

  • 一部のアプリケーションにUTF-8として認識させたい

  • ExcelでCSVを開く前提がある

  • 文字コード判定を補助したい

一方で、BOMがあると困る場面もあります。

  • 設定ファイルの先頭キーにBOMが混ざる

  • CSVの最初のヘッダー名にBOMが付く

  • BOM非対応のシステムでエラーになる

  • プログラムが先頭文字を正しく処理できない

C#では、BOMなしUTF-8は次のように指定できます。

C#
Encoding utf8WithoutBom = new UTF8Encoding(false);

BOM付きUTF-8は次のように指定できます。

C#
Encoding utf8WithBom = new UTF8Encoding(true);

10-5. 文字コードを完全に自動判定できますか?

完全な自動判定はできません。

BOMがある場合は比較的判定しやすいですが、BOMなしUTF-8、Shift_JIS、EUC-JPなどは、内容によっては誤判定される可能性があります。特に英数字だけのファイルでは、複数の文字コードで同じように見えることがあります。

そのため、文字コードは自動判定に頼るのではなく、次の順番で確認するのがおすすめです。

  1. 仕様書で確認する

  2. HTTPヘッダーやメタ情報で確認する

  3. BOMを確認する

  4. ファイル作成元の設定を確認する

  5. 必要に応じて自動判定を補助的に使う

業務システムでは、文字コードを設定値として持たせ、UTF-8かShift_JISかを明示的に選べるようにしておくと運用しやすくなります。

まとめ

C#で文字コードを扱うときのポイントは、stringと外部データの違いを理解することです。

C#のstringは内部的にUTF-16として扱われます。一方、ファイル、CSV、Web、API、外部コマンド、標準出力などでは、UTF-8やShift_JISなどの文字コードを使ってバイト列との変換が行われます。

基本的な変換にはSystem.Text.Encodingクラスを使います。

C#
byte[] bytes = Encoding.UTF8.GetBytes("こんにちは");
string text = Encoding.UTF8.GetString(bytes);

UTF-8を扱う場合は、Encoding.UTF8new UTF8Encoding(false)を使います。

C#
Encoding utf8 = Encoding.UTF8;
Encoding utf8WithoutBom = new UTF8Encoding(false);

Shift_JISを扱う場合は、.NET Core.NET 5以降ではEncoding.RegisterProviderが必要です。

C#
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
Encoding sjis = Encoding.GetEncoding("shift_jis");

文字化けを防ぐには、読み込み時と書き込み時の文字コードを一致させ、Encoding.Defaultや自動判定に頼りすぎないことが大切です。

新規開発ではUTF-8を基本にしつつ、外部システムやExcel連携などで必要な場合だけShift_JISを使うのが現実的です。

文字コードのトラブルは、原因が見えにくい一方で、仕組みを理解すれば確実に切り分けられます。C#でファイル入出力や外部連携を行うときは、必ず文字コードを明示し、UTF-8、Shift_JIS、BOM、変換不可文字の扱いを意識して実装しましょう。