こんにちは。「Javaを復習する初心者」です。
今回はBOM付きUTF-8ファイルの読み取りについての注意を確認しました。
テキストファイルを編集するとき、テキストエディタMeryというソフトを使っているのですが、UTF-8でテキストファイルを保存する場合、UTF-8(BOM付き)とUTF-8(BOM無し)という種類が選べます。wikipediaで調べた結果、バイトオーダーマークというデータの有無のことのようです。UTF-8のバイトオーダーマークは「0xEF 0xBB 0xBF」だそうです。
BOM無しと有りで実験
ではBOM付きテキストファイルをJavaで読み込んだ場合、1文字目の扱いはどうなるのか、実験してみました。BOM無しと有りのテキストファイル2つを用意し、「2147483647 2 a b」という内容で保存しました。以下のようにString型変数targetに最初の文字を格納しました。
ソース抜粋
String target = br.readLine().split(" ")[0];
以下のように文字の出力、長さとバイト列の出力をしました。
ソース抜粋
System.out.println("文字: " + target);
System.out.println("長さ: " + target.length());
System.out.print("バイト列: ");
for (byte b : target.getBytes()) {
System.out.print(Integer.toHexString(b) + " ");
}
結果は以下のようになりました。
BOM無し
文字: 2147483647
長さ: 10
バイト列: 32 31 34 37 34 38 33 36 34 37
BOM有り
文字: 2147483647
長さ: 11
バイト列: ffffffef ffffffbb ffffffbf 32 31 34 37 34 38 33 36 34 37
上記のように出力された文字に変化はありませんでした。長さはBOM有りだと1多く、バイト列は先頭にffffffef ffffffbb ffffffbfが付与されています。ちなみに2進数だと11111111111111111111111111101111 11111111111111111111111110111011 11111111111111111111111110111111です。「0xEF 0xBB 0xBF」と少し違いますが、エディタの問題でしょうか。あまり深く考えないことにします。
Integer#parseInt
次にInteger.parseIntを実行してみましたが、BOM付きの場合は以下のエラーが出ました。
エラー
Exception in thread "main" java.lang.NumberFormatException: For input string: "2147483647"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.lang.Integer.parseInt(Integer.java:615)
at practice.Hello20160821.test(Hello20160821.java:36)
at practice.Hello20160821.main(Hello20160821.java:15)
BOMの部分が影響しているらしく、NumberFormatExceptionが発生しました。
それではnew BigInteger(target)ならば大丈夫なのではないだろうか、と思いましたが、以下のエラーが出ました。
エラー
Exception in thread "main" java.lang.NumberFormatException: For input string: "2"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Integer.parseInt(Integer.java:580)
at java.math.BigInteger.<init>(BigInteger.java:461)
at java.math.BigInteger.<init>(BigInteger.java:597)
at practice.Hello20160821.test(Hello20160821.java:38)
at practice.Hello20160821.main(Hello20160821.java:16)
NumberFormatExceptionが発生しました。なぜ「For input string」の対象が「2」なのか不明です。深く考えないことにしました。
どうやらBOM付きで1文字目の数字は変換できないようです。BOMを知らないと気づかないエラーだと思います。