Чтение UTF-8 - спецификация - PullRequest
       41

Чтение UTF-8 - спецификация

59 голосов
/ 04 февраля 2011

Я читаю файл через 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>

Ответы [ 9 ]

69 голосов
/ 04 февраля 2011

В Java вы должны вручную использовать спецификацию UTF8, если она есть.Это поведение задокументировано в базе данных ошибок Java, здесь и здесь .Пока не будет исправлений, потому что это сломает существующие инструменты, такие как JavaDoc или парсеры XML. Apache IO Commons предоставляет BOMInputStream для решения этой ситуации.

Посмотрите на это решение: Обработка файла UTF8 с помощью спецификации

32 голосов
/ 04 февраля 2011

Самым простым исправлением, вероятно, является просто удаление результирующего \uFEFF из строки, так как оно вряд ли появится по любой другой причине.

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

Также см. этот отчет об ошибке в Гуаве

24 голосов
/ 21 декабря 2012

Использование библиотеки Apache Commons .

Класс: 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();
}
6 голосов
/ 25 мая 2016

Вот как я использую Apache BOMInputStream, он использует блок try-with-resources.Аргумент «false» указывает объекту игнорировать следующие спецификации (мы используем текстовые файлы «без спецификации», ха-ха):

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)

}
1 голос
/ 12 февраля 2018

Рассмотрим UnicodeReader от 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 голос
/ 01 июля 2017

Использование 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();

В результате у нас есть ArrayList с именем "ari" со всеми символами из файла "1.txt", исключая спецификацию.

1 голос
/ 27 февраля 2017

Упоминается здесь , что обычно это проблема с файлами в Windows.

Одним из возможных решений было бы сначала запустить файл через такой инструмент, как dos2unix.

0 голосов
/ 20 марта 2019

Если кто-то хочет сделать это со стандартом, это будет способ:

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 голосов
/ 26 октября 2017

Самый простой способ обойти спецификацию

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