もあいのモヤブロ

日々のモヤモヤをあれこれと書き連ねます。

EXCELで文字化けしないCSVファイルを吐くには「BOM」がいるらしい

私が中学生ぐらいの頃、「BOMB!」というアイドル雑誌がありました(今もあるようです)。
某アイドルの水着グラビアにドキドキした清く淡い思い出があります。

 

という話ではなくて。

 

先日「サーバ上で作成したCSVファイルをEXCELで開くと文字化けする」という事象がありまして、
もしかしたら「BOM」というものが関係している!?と思い、調べてみました。

『...
バイトオーダーマーク (byte order mark) あるいはバイト順マーク(バイトじゅんマーク)は通称BOM(ボム)といわれる、Unicodeの符号か形式で符号化したテキストの先頭につける数バイトのデータのことである。このデータを元にUnicodeで符号化されていることおよび符号化の種類の判別に使用する。
(中略)
...
UTF-8は既存のASCIIなどのデータしか読み込みが行えない場合でも正常に扱えるようにするための符号化であるが、このデータがついていることによりASCIIしか読み込めないプログラムではデータが正常に処理できなくなる問題が発生する場合がある
...』
wikipedia:バイトオーダーマークより(赤太線部は筆者)

な、なんだってー!?

 

さらに、

『...
バイト順マークの使用について
(中略)
逆にこのシーケンスがないとUTF-8と認識できないプログラムも存在する。とくにASCII部以外の文字が少ない場合に誤認することが多い (たとえば、Microsoft Excelでは、CSVファイルを開くとき、このシーケンスが付加されていないUTF-8の場合は正常に読み込むことができない。
(中略)
...』
wikipedia:UTF-8より(赤太線部は筆者)

 なんじゃそりゃー!知らなかったよ...。

 

というわけで、プログラムからCSVファイルを作成してこれをEXCELから開く場合は、以下のようにファイルの先頭にBOMをつけてあげなければならないようです(以下はJavaの例)。

import java.io.*;

class CSVOutputSample {

public static void main(String args[]) {

FileOutputStream fos = null;
BufferedWriter bw = null;

try {
fos = new FileOutputStream("Test.csv");
fos.write( 0xef );
fos.write( 0xbb );
fos.write( 0xbf );
bw = new BufferedWriter( new OutputStreamWriter( fos, "UTF8" ));
bw.write("日本語, Alphabet, カタカナ, 1\r\n");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bw != null) {
try {
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}