業務でファイル操作に関連する処理を実装したのですが、UTF-8(BOM付き)ファイルから
BOMを削除するための方法を学んだので今後のためにまとめてみます。
そもそもBOMとは?
まず、そもそもBOMとは一体何者なのでしょうか?
BOMとはざっくりいってしまえば
Unicode系文字コードで作成されたファイルの先頭に付く目印です。
UTF-8では0xEF 0xBB 0xBFの3バイトで表現されます。
BOMは普通メモ帳などでは見ることはできませんが、実際にはファイルの中身の最初に
BOMが付いており、コンピュータ側で読み取る際にもそのように解釈して実行します。
そして、目印として主に2つの役割を持ちます。
- Unicode系の文字コードで記述されていることを示すためのもの
- UTF-16、UTF-32においてエンディアンと呼ばれるビットの並び順を指定するためのもの。
並べる順序によって、
・ ビッグエンディアン(上位バイトから順番に並べる)
・ リトルエンディアン(下位バイトから順番に並べる)
の2種類がある
なぜUTF-8(BOM付き)が存在するのか?
UTF-16、UTF-32のように2バイト以上の文字コードで文字との対応付けを行う際には
エンディアンの並び順を指定するためにBOMが使われます。
しかし、UTF-8のように1バイトの文字コードで対応付けを行っている場合には
エンディアンを指定する必要なんてありません。
では、なぜUTF-8(BOM付き)が存在するのでしょうか?
調べていくと、ExcelがCSVを開く際の仕様に原因があることがわかりました。
ExcelがCSVを開くときにはShift-JISで開こうとするため、BOMなしのUTF-8で
書かれたファイルを読み込もうとすると文字化けしてしまうのです。
これを防ぐためにBOMを付けてCSVを開くときにもUnicode系の文字コードで
読み込むように指定する必要があるのです。
BOMを削除する方法
では、本題となっているBOMを削除するための方法を説明していきます。
JavaではそもそもUTF-8にBOMが付いている場合を想定していません。
そのため、BOM付きのファイルを読み込む際にはBOMを他の文字と
同様のものとして扱い、BOMを削除しません。
そのため、BOMを削除する場合は別途そのような処理を実装する必要があります。
// BOMをUnicodeコード表示したもの
public static final String BOM = "\uFEFF";
/**
* ファイルにBOMが含まれていた場合、
* BOMなしに変換する。
*
* @param s ファイル文字列
* @return BOMなしのファイル文字列
*
*/
private static String removeUTF8BOM(String s) {
if (s.startsWith(BOM)) {
// ファイルの先頭より後ろの文字列を読み込む
s = s.substring(1);
}
return s;
}
なお、もう一つの方法としてapacheが提供しているクラスライブラリを使う方法もあります。
詳しい仕様は以下を参照してください。