web-dev-qa-db-ja.com

UTF-8の読み取り-BOMマーカー

FileReaderを使用してファイルを読み取っています。ファイルはUTF-8でデコードされ(BOMを使用)、問題は次のとおりです。ファイルを読み取って文字列を出力しますが、悲しいことにBOMマーカーも出力されます。なぜこれが起こるのですか?

fr = new FileReader(file);
br = new BufferedReader(fr);
    String tmp = null;
    while ((tmp = br.readLine()) != null) {
    String text;    
    text = new String(tmp.getBytes(), "UTF-8");
    content += text + System.getProperty("line.separator");
}

最初の行の後の出力

?<style>
60
onigunn

Javaでは、UTF8 BOMが存在する場合は手動で消費する必要があります。この動作は、Javaバグデータベース、 here および here に記載されています。既存のツールが破損するため、現時点では修正はありません。 JavaDocやXMLパーサーなど Apache IO Commons は、この状況を処理するBOMInputStreamを提供します。

このソリューションを見てください: BOMでUTF8ファイルを処理する

70
RealHowTo

最も簡単な解決策は、おそらく、結果の\uFEFFを文字列から削除することです。これは、他の理由で表示される可能性は極めて低いからです。

tmp = tmp.replace("\uFEFF", "");

このGuavaバグレポート も参照してください

33
finnw

Apache Commons library を使用します。

クラス: org.Apache.commons.io.input.BOMInputStream

使用例:

String defaultEncoding = "UTF-8";
InputStream inputStream = new FileInputStream(someFileWithPossibleUtf8Bom);
try {
    BOMInputStream bOMInputStream = new BOMInputStream(inputStream);
    ByteOrderMark bom = bOMInputStream.getBOM();
    String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
    InputStreamReader reader = new InputStreamReader(new BufferedInputStream(bOMInputStream), charsetName);
    //use reader
} finally {
    inputStream.close();
}
24
peenut

Apache BOMInputStreamの使用方法は次のとおりです。try-with-resourcesブロックを使用しています。 「false」引数は、オブジェクトに次のBOMを無視するよう指示します(安全上の理由から「BOMなし」テキストファイルを使用します)。

try( BufferedReader br = new BufferedReader( 
    new InputStreamReader( new BOMInputStream( new FileInputStream(
       file), false, ByteOrderMark.UTF_8,
        ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE,
        ByteOrderMark.UTF_32BE, ByteOrderMark.UTF_32LE ) ) ) )
{
    // use br here

} catch( Exception e)

}
6
snakedoctor

Apache Commons IO を使用します。

たとえば、次のコード(ラテン文字とキリル文字の両方を含むテキストファイルの読み取りに使用)を見てみましょう。

String defaultEncoding = "UTF-16";
InputStream inputStream = new FileInputStream(new File("/temp/1.txt"));

BOMInputStream bomInputStream = new BOMInputStream(inputStream);

ByteOrderMark bom = bomInputStream.getBOM();
String charsetName = bom == null ? defaultEncoding : bom.getCharsetName();
InputStreamReader reader = new InputStreamReader(new BufferedInputStream(bomInputStream), charsetName);
int data = reader.read();
while (data != -1) {

 char theChar = (char) data;
 data = reader.read();
 ari.add(Character.toString(theChar));
}
reader.close();

結果として、BOMを除くファイル「1.txt」のすべての文字を含む「ari」という名前のArrayListがあります。

1
pawman

nicodeReader を検討してください。この機能はすべてGoogleから提供されています。

Charset utf8 = Charset.forName("UTF-8"); // default if no BOM present
try (Reader r = new UnicodeReader(new FileInputStream(file), utf8)) {
    ....
}

Mavenの依存関係:

<dependency>
    <groupId>com.google.gdata</groupId>
    <artifactId>core</artifactId>
    <version>1.47.1</version>
</dependency>
1
Adrian Smith

here これは通常、Windows上のファイルの問題であるということです。

1つの可能な解決策は、最初にdos2unixなどのツールを使用してファイルを実行することです。

1
Drake Sobania

BOMをバイパスするために見つけた最も簡単な方法

BufferedReader br = new BufferedReader(new InputStreamReader(fis));    
while ((currentLine = br.readLine()) != null) {
                    //case of, remove the BOM of UTF-8 BOM
                    currentLine = currentLine.replace("","");
0
David

誰かが標準でそれをしたい場合、これは方法です:

public static String cutBOM(String value) {
    // UTF-8 BOM is EF BB BF, see https://en.wikipedia.org/wiki/Byte_order_mark
    String bom = String.format("%x", new BigInteger(1, value.substring(0,3).getBytes()));
    if (bom.equals("efbbbf"))
        // UTF-8
        return value.substring(3, value.length());
    else if (bom.substring(0, 2).equals("feff") || bom.substring(0, 2).equals("ffe"))
        // UTF-16BE or UTF16-LE
        return value.substring(2, value.length());
    else
        return value;
}
0
Markus