« ◆決定!縦長の黄金比と横長の黄金比 | トップページ | ◆光の特異点:光の波のQ&Q »

JavaでUTF-8のBOMに対処する

この記事は「 Javaでファイルオープン:文字コードや追加モードなど」の補助記事です。

 JavaでBOM付きUTF-8ファイルを読む

媒体上の文字コード規格、UTF-8には、規格策定者の迷いのため 一時期、先頭に3バイトのBOMと呼ばれる、バイト並び識別マーク を置く仕様がありました。
現在はBOMはまず使われることはありませんが、Windows付属の「メモ帳」という 簡易エディタでUTF-8ファイルをうっかり作成してしまうと、ファイル先頭に BOMが付いてしまいます。

残念なことにJavaではBOM付きのUTF-8ファイルをまともに 読むことができません。

 先頭がBOMの場合スキップする方法

対処法は色々考えられますが、ここでは、BufferedInputStreamを被せ、 先頭がBOMの場合スキップし、BOMでない場合先頭まで巻き戻す形を 示します。

import java.io.*;
public class Test1 {
   /** テキストファイルを読み込み用にオープンする */
   public static BufferedReader  openTextFileR(
                        String fileName
                       ,String charSet
                       )throws Exception{
      return new BufferedReader(
                 new InputStreamReader(
                     skipUTF8BOM(
                        new FileInputStream(
                            new File(fileName))
                       ,charSet)
                    ,charSet));
      }
   /** UTF-8のBOMをスキップする */
   public static InputStream skipUTF8BOM(
                        InputStream is
                       ,String      charSet
                        )throws Exception{
      if( !charSet.toUpperCase().equals("UTF-8") ) return is;
      if( !is.markSupported() ){
         // マーク機能が無い場合BufferedInputStreamを被せる
         is= new BufferedInputStream(is);
         }
      is.mark(3); // 先頭にマークを付ける
      if( is.available()>=3 ){
         byte b[]={0,0,0};
         is.read(b,0,3);
         if( b[0]!=(byte)0xEF ||
             b[1]!=(byte)0xBB ||
             b[2]!=(byte)0xBF ){
            is.reset();// BOMでない場合は先頭まで巻き戻す
            }
         }
      return is;
      }
   public static void main(String[] args_){
      try{
         String         line;
         BufferedReader br;
         // BOM処理なし
         br = new BufferedReader(new InputStreamReader(
                                    new FileInputStream(
                                         new File(args_[0]))
                                   ,"utf-8"));
         while( (line=br.readLine())!=null ) System.out.println(line);
         br= new BufferedReader(new InputStreamReader(
                                    new FileInputStream(
                                         new File(args_[1]))
                                   ,"utf-8"));
         while( (line=br.readLine())!=null ) System.out.println(line);
         // BOM処理あり
         br= openTextFileR(args_[0],"utf-8");
         while( (line=br.readLine())!=null ) System.out.println(line);
         br= openTextFileR(args_[1],"utf-8");
         while( (line=br.readLine())!=null ) System.out.println(line);
         }
      catch(Exception e){
         e.printStackTrace(System.err);
         }
      }
   }
通常文字コードを指定するファイルのオープンは次のようになります。
      BufferedReader br=new BufferedReader(
                 new InputStreamReader(
                    new FileInputStream(
                            new File(fileName))
                    ,charSet));
このFileInputStreamに関数skipUTF8BOM()を作用させています。 skipUTF8BOM()関数は文字コードがutf-8の場合、先頭の3バイトを読み BOMの場合はそのまま続くデータを読むように、BOMでない場合は 先頭まで巻き戻します。

他の方法としてはBOMがある場合そのまま読み進み、ない場合はオープンしなおす といった方法も可能です。

 サンプル

BOM付き、BOM無しのファイルを含むサンプルを置きました。

  Test1.java     : プログラム
  utf8_BOM.txt   : BOM付きUTF-8テキストファイル
  utf8_noBOM.txt : BOM無しUTF-8テキストファイル
  build.xml      : ANTビルドファイル
  AA10_test.bat  : ANTを起動し試験を実行するバッチファイル

Test1.javaは先に載せたプログラムと同じです。BOM対応無しで BOM付、BOM無しファイルを読み、次にBOM対応した形で読み込みます。
次の表示が出るはずです。
     [java] ?あいうえお
     [java] あいうえお
     [java] あいうえお
     [java] あいうえお
?はBOMのため正確に読めなかった文字を表しています。

 対応ライブラリ

Javaでファイルオープン:文字コードや追加モードなど」で紹介した ライブラリは1.28からUTF-8のBOM対応を行っています。
利用者はBOMに関して意識する必要はありません。

例えばテキストファイルの読み込み用オープンは次のような形で行います。

   BufferedReader br = hiU.openTextFileR("test.txt","utf-8");
これでUTF-8-BOMの有り無しに関わらず読み込みができます。
簡単である上、視認性が極めて高いと考えています。

ライブラリ説明

ダウンロードページも含むライブラリ全体の説明は にあります。
オツアンドサンズのホームページは です。

|

« ◆決定!縦長の黄金比と横長の黄金比 | トップページ | ◆光の特異点:光の波のQ&Q »

トラックバック


この記事へのトラックバック一覧です: JavaでUTF-8のBOMに対処する:

« ◆決定!縦長の黄金比と横長の黄金比 | トップページ | ◆光の特異点:光の波のQ&Q »