C#を使用してアプリケーションを開発する際、避けて通れないのが「文字エンコーディング」の問題です。
特に日本では、世界標準であるUTF-8と、古くからWindows環境やレガシーシステムで利用されてきたShift-JIS(CP932)の混在が頻繁に起こります。
Web APIから取得したデータはUTF-8なのに、出力するCSVファイルはShift-JISでなければならない、といったケースは実務でも非常に多いでしょう。
この記事では、C#(.NET)を使用してUTF-8とShift-JISを相互に変換する具体的な方法を、初心者の方でも理解しやすいように詳しく解説します。
最新の.NET環境における注意点から、ファイル入出力への応用まで、現場で即戦力となる知識を凝縮してお届けします。

文字エンコーディングの基礎知識
プログラミングにおける文字エンコーディングとは、コンピュータが理解できる「数値(バイト列)」と、人間が理解できる「文字」をどのように対応させるかという変換ルールのことです。
このルールが一致していないと、いわゆる「文字化け」が発生します。
UTF-8とShift-JISの違い
UTF-8は世界中の文字を一つの体系で扱うことができるマルチバイト文字エンコーディングであり、現代のインターネットにおける標準です。
一方、Shift-JISは日本語を扱うために特化して開発されたエンコーディングで、主に日本のWindows環境で普及してきました。
これらのエンコーディングは、同じ「あ」という文字でも、内部的な数値表現が全く異なります。
| 文字 | UTF-8 (16進数) | Shift-JIS (16進数) |
|---|---|---|
| あ | E3 81 82 | 82 A0 |
| い | E3 81 84 | 82 A2 |
| A | 41 | 41 |
上記のように、英数字(ASCII)は共通ですが、日本語はバイト数も値も異なります。
このため、適切な変換処理が必要になるのです。

.NET Core/5以降での事前準備
現代のC#開発(.NET Core、.NET 5、.NET 6、.NET 7、.NET 8以降)では、軽量化のためにデフォルトでサポートされているエンコーディングが制限されています。
実は、Shift-JISは標準では組み込まれていません。
そのため、Shift-JISを扱うには、事前に「コードページエンコーディング」を有効にするための手順が必要です。
NuGetパッケージの導入
まず、プロジェクトにSystem.Text.Encoding.CodePagesというパッケージを導入する必要があります。
Visual StudioのNuGetパッケージマネージャー、またはdotnet CLIで以下のコマンドを実行してください。
dotnet add package System.Text.Encoding.CodePages
エンコーディングの登録処理
プログラムの開始時(Mainメソッドなど)で、一度だけ以下のコードを呼び出す必要があります。
これを忘れると、Shift-JISを取得しようとした際にNotSupportedExceptionが発生します。
// エンコーディングプロバイダを登録する
// これにより、Shift-JISなどの追加エンコーディングが利用可能になる
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
この一行を追加することで、Encoding.GetEncoding("shift_jis")という記述が有効になります。

UTF-8からShift-JISへ変換する方法
それでは、具体的な変換コードを見ていきましょう。
最も一般的なのは、C#内部で保持しているstring(中身はUTF-16)を、Shift-JISのバイト配列に変換するパターンです。
基本的な変換の仕組み
C#のstring型は、メモリ内では常にUTF-16として保持されています。
そのため、「UTF-8からShift-JISへの変換」という処理は、実際には「UTF-16の文字列をShift-JISのバイト配列として取り出す」という操作になります。
サンプルコード:文字列をShift-JISのバイト配列にする
以下のコードは、日本語を含む文字列をShift-JIS形式のバイト配列に変換し、その中身を確認する例です。
using System;
using System.Text;
class Program
{
static void Main()
{
// 1. Shift-JISを扱えるように登録(現代の.NETでは必須)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// 2. 変換元の文字列
string sourceText = "こんにちは、C#の世界へ!";
// 3. Shift-JISのエンコーディングオブジェクトを取得
// 日本語Windowsの標準である「CP932」を指定するのが一般的
Encoding sjisEnc = Encoding.GetEncoding("shift_jis");
// 4. 文字列をShift-JISのバイト配列に変換
byte[] sjisBytes = sjisEnc.GetBytes(sourceText);
// 結果の出力
Console.WriteLine($"元の文字列: {sourceText}");
Console.WriteLine("Shift-JISのバイト列(16進数):");
foreach (byte b in sjisBytes)
{
Console.Write($"{b:X2} ");
}
Console.WriteLine();
}
}
元の文字列: こんにちは、C#の世界へ!
Shift-JISのバイト列(16進数):
82 B1 82 F1 82 C9 82 BF 82 CD 81 41 43 23 82 CC 90 A2 82 AD 82 D矛盾B 81 49
まず、Encoding.GetEncoding("shift_jis")でShift-JIS用の変換器を作成します。
次に、そのオブジェクトのGetBytesメソッドに文字列を渡すだけで、Shift-JIS形式のバイト配列が得られます。
これは、ファイルをShift-JISで保存したい場合や、古い通信プロトコルでデータを送信したい場合に必須の処理です。
Shift-JISからUTF-8へ変換する方法
次に、外部から読み込んだShift-JISのデータを、C#で扱いやすいUTF-8(文字列)に変換する方法を解説します。
例えば、Shift-JISで書かれたテキストファイルを読み込む際などがこれに該当します。
サンプルコード:Shift-JISのバイト配列を文字列にする
バイト配列として受け取ったデータを、string型に復元する処理です。
using System;
using System.Text;
class Program
{
static void Main()
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// 仮のShift-JISデータ(「C#」という文字)
byte[] sjisBytes = { 0x43, 0x23 };
// Shift-JISのエンコーディングを取得
Encoding sjisEnc = Encoding.GetEncoding("shift_jis");
// Shift-JISのバイト配列を文字列(UTF-16)にデコード
string decodedText = sjisEnc.GetString(sjisBytes);
// デコードした文字列をUTF-8のバイト配列に変換
byte[] utf8Bytes = Encoding.UTF8.GetBytes(decodedText);
Console.WriteLine($"デコードされた文字列: {decodedText}");
Console.WriteLine("UTF-8のバイト列(16進数):");
foreach (byte b in utf8Bytes)
{
Console.Write($"{b:X2} ");
}
}
}
デコードされた文字列: C#
UTF-8のバイト列(16進数):
43 23
GetStringメソッドを使用することで、特定のエンコーディングに基づいたバイト配列をC#の標準文字列へと変換できます。
一度string型にしてしまえば、あとはEncoding.UTF8.GetBytesを使うことで簡単にUTF-8のバイト列を取得することが可能です。

ファイル入出力におけるエンコーディング指定
実際のアプリケーション開発では、文字列を直接変換するよりも、「ファイルをShift-JISで読み書きする」という場面の方が多いでしょう。
C#のStreamReaderやStreamWriterは、コンストラクタでエンコーディングを指定できます。
Shift-JIS形式でファイルを書き出す
using System.IO;
using System.Text;
public void WriteSjisFile(string filePath, string content)
{
// Shift-JISエンコーディングの取得
Encoding sjisEnc = Encoding.GetEncoding("shift_jis");
// 第3引数にエンコーディングを指定して書き込み
using (StreamWriter sw = new StreamWriter(filePath, false, sjisEnc))
{
sw.Write(content);
}
}
Shift-JIS形式のファイルを読み込む
using System.IO;
using System.Text;
public string ReadSjisFile(string filePath)
{
Encoding sjisEnc = Encoding.GetEncoding("shift_jis");
// StreamReaderでエンコーディングを指定して読み込み
using (StreamReader sr = new StreamReader(filePath, sjisEnc))
{
return sr.ReadToEnd();
}
}
注意点:BOM(Byte Order Mark)について
UTF-8には「BOM」と呼ばれる、ファイルの先頭に付与される識別符号が存在します。
C#のEncoding.UTF8はデフォルトでBOMを付与する設定になっていることが多いため、BOMなしのUTF-8を要求される場合は、new UTF8Encoding(false)を使用するようにしましょう。

文字化けを防ぐためのベストプラクティス
エンコーディングの変換で失敗しないためには、いくつかの重要な原則があります。
1. 変換できない文字(サロゲートペアなど)への対応
Shift-JISはUTF-8に比べて表現できる文字数が圧倒的に少ないです。
そのため、UTF-8には存在するがShift-JISには存在しない文字(例:特殊な漢字や絵文字)を変換しようとすると、デフォルトでは「?」に置き換わってしまいます。
これを防ぐためには、変換時に例外を投げるように設定するか、独自の代替文字を指定する「フォールバック」の設定を検討してください。
2. 「CP932」と「Shift-JIS」の使い分け
C#でEncoding.GetEncoding("shift_jis")を指定した場合、通常はWindows拡張文字を含むCP932として扱われます。
丸囲み数字(①②③)や、(株)などの特殊記号を正しく扱いたい場合は、このデフォルトの挙動で問題ありません。
3. 文字列操作は常に「string型」で行う
バイト配列の状態で文字を連結したり分割したりするのは非常に危険です。
特にマルチバイト文字の途中でバイナリを分断してしまうと、修復不可能な文字化けを招きます。
必ず、「バイト配列からstringへデコード → string型で加工 → 必要なエンコーディングでバイト配列へエンコード」という手順を徹底しましょう。

まとめ
C#におけるUTF-8とShift-JISの相互変換は、基本さえ押さえれば決して難しくありません。
現代の.NET開発においては、CodePagesEncodingProviderの登録が必須であるという点が最大の注意点です。
この記事のポイントを振り返ります。
- 現代の.NETでは、
Encoding.RegisterProviderでShift-JISを有効化する必要がある。 - 変換の核心は、
Encoding.GetBytes(文字列→バイト列)とEncoding.GetString(バイト列→文字列)の使い分け。 - ファイル入出力では、
StreamReader/Writerの引数でエンコーディングを指定する。 - Shift-JISで表現できない文字による「?」化けに注意する。
これらの知識を活用して、文字化けに悩まされない堅牢なアプリケーションを構築してください。
データの入り口と出口で正しくエンコーディングを制御することが、日本のシステム開発における品質向上の第一歩となります。
