C#では、TextWriterクラスを使って、容易に任意の文字セットのテキストファイルを出力できます。
Windowsにおける文字セット
昔(1990年代)は、Windowsでは各言語に特化した文字セット(たとえば日本語であればシフトJIS文字セット)を使うことがほとんどでした。しかし、特定の言語に特化した文字セットのテキストファイルを他の言語OSなどで読み込むと文字化けが生じました。
そのため、Windowsでは、次第に各言語で共通の文字セットとして一文字を16ビットで表すユニコード(Unicode)が使われるようになりました。
Windowsのネイティブ系のWin32 APIでは16ビットユニコードが使われていますし、マネージド系の.NETでも16ビットユニコードが使われています。
UTF-8
UTF-8は、ユニコードを8ビット符号単位(1〜4バイトの可変長)での文字符号化形式および文字符号化スキームです。簡単にいうと、ユニコードの一文字を1バイトから4バイトで表現する方法です。UTF-8では、対象がASCII文字の場合は1バイトで表現できるためデータサイズが大きくなることはありません。しかし、対象が非ASCIIのラテン文字では2バイト、漢字などでは3バイトにになり、データサイズが大きくなります。
現在では、データ交換方式・ファイル形式としてUTF-8が一般的に使われる傾向にあります。
BOM (Byte Order Mark, バイト順マーク)
16ビットユニコードの場合、一文字が2バイトで表現されるのですが、その2バイトをどの順番で保存するかで2種類のパターンが考えられます。下位バイト→上位バイト(リトルエンディアン) と上位バイト→下位バイト(ビックエンディアン) です。ユニコードをPCのメモリ上で扱うときは、メモリ上に保存するときにどちらかに統一して扱えば問題ありません。しかし、ファイルなど外部から入力される16ビットユニコードの場合、ファイルを作成したときにどちらのバイト順で保存したかがわからないと正しく扱うことができません。これを、区別できるようにユニコードファイルの先頭に0xfeffを追加することがあります。読み込むときに、0xfe, 0xff の順番で現れればビックエンディアンであり、0xff, 0xfeの順番であればリトルエンディアンであることがわかります。
このファイルの先頭に追加する0xfffeをBOM(Byte Order Mark, バイト順マーク)といいます。16ビットユニコードの場合は、BOMはバイトの並び順を表しますが、UTF-8でもBOM (0xef 0xbb 0xbf, 0xfffeのUTF-8表現) を追加することがあります。ただし、UTF-8でのBOMは、バイト順を表すものではなく、テキストファイルのエンコーディングがUTF-8であることを表します。
C#で文字列をUTF-8でファイル出力する
現在では、データ交換方式・ファイル形式としてUTF-8が一般的に使われる傾向にあるため、UTF-8でファイル出力したいことは多くあります。
C#でUTF-8を指定してファイル出力するのは簡単です。StreamWriterクラスを使います。BOM有のUTF-8ファイル出力とBOM無しのUTF-8ファイル出力では、指定する文字エンコーディングが異なるだけで、ほぼ同じです。
UTF-8ファイル出力(BOM有り)
BOM有のUTF-8の場合は、既定で用意されているエンコーディングの値(System.Text.Encoding.UTF8)を利用できます。
var utf8Encoding = System.Text.Encoding.UTF8;
using (var streamWriter = new StreamWriter(outputUtf8File, false, utf8Encoding))
{
await streamWriter.WriteAsync(stringData);
}
UTF-8ファイル出力(BOM無し)
BOM無のUTF-8の場合は、既定で用意されているエンコーディングの値(System.Text.Encoding.UTF8)は利用できず、独自のエンコーディング値(new System.Text.UTF8Encoding(false))を作成して利用します。
var utf8Encoding = new System.Text.UTF8Encoding(false);
using (var streamWriter = new StreamWriter(outputUtf8File, false, utf8Encoding))
{
await streamWriter.WriteAsync(stringData);
}
今回は、C#でのUTF-8ファイル出力(BOM有り・無し)の方法の投稿でした。