shift-jis と utf-8 の混在問題に関する記事(リンクリスト)に戻る
この記事は情技師(ITエンジニア)向けの記事です。
.net C# の StreamReader によるBOMの有無判定の記事を書いた次いでに、StreamWriter で BOM有り・BOMなしの utf テキストファイルを作成するサンプルコードをここに載せる。
この手のサンプルコードは検索すると沢山出てくるので、必ずしもこのコードでなくても良いと思う。
好きなサンプルコードを探すと良い。
コードは .net framework 4.0 上でテストしている。
バージョンに依存するようなコードでもないので、他のバージョンや .net core でも使えると思う。
Visual Studio で「コンソールアプリケーション」でプロジェクトファイルを作成してコピーしてビルドする。
以下が全サンプルコードである。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace StreamWriterForBOM_sample
{
class Program
{
static void Main(string[] args)
{
string fileName;
if (args.Length < 1)
{
fileName = "newFile.txt";
}
else
{
fileName = args[0];
}
string inputEncodingName;
if (args.Length < 2)
{
inputEncodingName = "utf-8";
}
else
{
inputEncodingName = args[1];
}
bool existBOM;
if (args.Length < 3)
{
existBOM = true;
}
else
{
if (args[2] == "false")
{
existBOM = false;
}
else
{
existBOM = true;
}
}
string text;
if(args.Length < 4)
{
text = "ABCDE.12345.!#$%.あいうえお.アイウエオ.アイウエオ.日本漢字,欄廊俠俱.China产乡.Taiwan說姊.Korea희편";
}
else
{
text = args[3];
}
string encodingName;
int codepage;
if (int.TryParse(inputEncodingName, out codepage))
{
encodingName = string.Empty;
}
else
{
encodingName = inputEncodingName;
}
try
{
Encoding encoding;
if (encodingName == string.Empty)
{
// utf-8
if (codepage == 65001)
encoding = new UTF8Encoding(existBOM);
// utf-16 Little En
else if (codepage == 1200)
encoding = new UnicodeEncoding(false, existBOM);
// utf-16 Big En
else if (codepage == 1201)
encoding = new UnicodeEncoding(true, existBOM);
// utf-32 Little En
else if (codepage == 12000)
encoding = new UTF32Encoding(false, existBOM);
// utf-32 Big En
else if (codepage == 12001)
encoding = new UTF32Encoding(true, existBOM);
// shift-jis etc.
else
encoding = Encoding.GetEncoding(codepage);
}
else
{
// utf-8
if (encodingName == "utf-8")
encoding = new UTF8Encoding(existBOM);
// utf-16 Little En
else if (encodingName == "utf-16")
encoding = new UnicodeEncoding(false, existBOM);
// utf-16 Big En
else if (encodingName == "unicodeFFFE")
encoding = new UnicodeEncoding(true, existBOM);
// utf-32 Little En
else if (encodingName == "utf-32")
encoding = new UTF32Encoding(false, existBOM);
// utf-32 Big En
else if (encodingName == "utf-32be")
encoding = new UTF32Encoding(true, existBOM);
// shift-jis etc.
else
encoding = Encoding.GetEncoding(encodingName);
}
using (var writer = new StreamWriter(fileName, true, encoding))
{
writer.Write(text);
}
}
catch (Exception ex)
{
Console.WriteLine("Error! : {0}", ex.ToString());
}
finally
{
Console.WriteLine("Created file the {0}.", fileName);
}
}
}
}
「コンソールアプリケーション」なので、コマンドプロンプトからこのコマンドを使用する。
コマンド引数は、「ファイル名」「エンコーディング名」「BOMの有無指定」「出力文字列」だ。
<コマンド名> <ファイル名> <エンコーディング名> <BOMの有無指定> <出力文字列>
全て省略可能である。
省略した場合は以下の値になる。
<ファイル名> "newFile.txt"
<エンコーディング名> "utf-8"
<BOMの有無指定> 有り
<出力文字列> "ABCDE.12345.!#$%.あいうえお.アイウエオ.アイウエオ.日本漢字,欄廊俠俱.China产乡.Taiwan說姊.Korea희편"
出力文字列には shift-jis では使用できない漢字を含めているので、これで shift-jis テキストを出力すると「日本漢字,」より後ろが文字化けする。
例えば、ファイル名「aaa.txt」で、shift-jis のテキストファイルを作成するなら以下のようにコマンド入力する。
<コマンド名> aaa.txt shift-jis
または
<コマンド名> aaa.txt shift-jis false テスト文字列
ファイル名「bbb.txt」で、BOM有り utf-8 のテキストファイルを作成するなら以下のようにコマンド入力する。
<コマンド名> bbb.txt utf-8 true
または
<コマンド名> bbb.txt utf-8 true テスト文字列
BOMなし utf-8 のテキストファイルなら、こうなる。
<コマンド名> bbb.txt utf-8 false
または
<コマンド名> bbb.txt utf-8 false テスト文字列
Encoding の作成
StreamWriter で UNICODEのテキストファイルを作成する場合は、Encoding のインスタンスを先に作成する。
Encoding encoding; //変数を用意する
Encoding のインスタンスは通常は Encoding.GetEncoding("エンコーディング名") で作成するが、これはBOMの有無の指定が出来ないので、BOMの有無を指定するなら UTF の種類によって以下の専用エンコーディングクラスを使用する。
UTF8Encoding : utf-8
UnicodeEncoding : utf-16LE, utf-16BE
UTF32Encoding : utf-32LE, utf-32BE
それぞれの専用エンコーディングクラスは utf-8 を除きコンストラクタの第一引数でBIG Endian か否かをboolean で指定し、第二引数でBOMの有無を指定する。
UTF8Encoding はBOMの有無を指定のみである。
以下のコードがそれに該当する。
Encoding encoding;
if (encodingName == string.Empty)
{
// utf-8
if (codepage == 65001)
encoding = new UTF8Encoding(existBOM);
// utf-16 Little En
else if (codepage == 1200)
encoding = new UnicodeEncoding(false, existBOM);
// utf-16 Big En
else if (codepage == 1201)
encoding = new UnicodeEncoding(true, existBOM);
// utf-32 Little En
else if (codepage == 12000)
encoding = new UTF32Encoding(false, existBOM);
// utf-32 Big En
else if (codepage == 12001)
encoding = new UTF32Encoding(true, existBOM);
// shift-jis etc.
else
encoding = Encoding.GetEncoding(codepage);
}
else
{
// utf-8
if (encodingName == "utf-8")
encoding = new UTF8Encoding(existBOM);
// utf-16 Little En
else if (encodingName == "utf-16")
encoding = new UnicodeEncoding(false, existBOM);
// utf-16 Big En
else if (encodingName == "unicodeFFFE")
encoding = new UnicodeEncoding(true, existBOM);
// utf-32 Little En
else if (encodingName == "utf-32")
encoding = new UTF32Encoding(false, existBOM);
// utf-32 Big En
else if (encodingName == "utf-32be")
encoding = new UTF32Encoding(true, existBOM);
// shift-jis etc.
else
encoding = Encoding.GetEncoding(encodingName);
}
encodingName <エンコーディング名>には、エンコーディング名とコードページのどちらでも指定入力できるように作っているので、最初の条件分岐で振り分けているが、if,else どちらも同じ事をしている。
入力されたエンコーディング名が、UNICODEに該当しなかったら Encoding.GetEncoding(encodingName) で Encoding インスタンスを作成する。
StreamWriter でBOM有無ファイルを作成する
ここまでやると後は簡単で、StreamWriterコンストラクタ に Encoding インスタンスを渡してインスタンス化して Write メソッドでファイルに出力するだけだ。
using (var writer = new StreamWriter(fileName, true, encoding))
{
writer.Write(text);
}
StreamWriterコンストラクタ の第二引数は既存ファイルに追記するかどうか指定している。
新規作成では関係ない。
ごらんのように、StreamWriter によるBOM有無のファイル出力は簡単だ。
このサンプルがお役に立てば幸いだ。