Подтвердить что ты не робот

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

Я читаю файл через FileReader - файл декодирован UTF-8 (с 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>
4b9b3361

Ответ 1

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

Взгляните на это решение: Обрабатывать файл UTF8 с спецификацией

Ответ 2

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

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

Также см. этот отчет об ошибке Guava

Ответ 3

Используйте библиотеку 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();
}

Ответ 4

Здесь, как я использую 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)

}

Ответ 5

Он упомянул here, что это обычно проблема с файлами в Windows.

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

Ответ 6

Затем я придумал подкласс Reader.

/*
 * Copyright (C) 2016 donizyo
 *
 */
package net.donizyo.io;

public class BOMReader extends BufferedReader {

    public static final String DEFAULT_ENCODING = "UTF-8";

    public BOMReader(File file) throws IOException {
        this(file, DEFAULT_ENCODING);
    }

    private BOMReader(File file, String encoding) throws IOException {
        this(new FileInputStream(file), encoding);
    }

    private BOMReader(FileInputStream input, String encoding) throws IOException {
        this(new BOMInputStream(input), encoding);
    }

    private BOMReader(BOMInputStream input, String encoding) throws IOException {
        super(new InputStreamReader(input, getCharset(input, encoding)));
    }

    private static String getCharset(BOMInputStream bomInput, String encoding) throws IOException {
        ByteOrderMark bom;

        bom = bomInput.getBOM();
        return bom == null ? encoding : bom.getCharsetName();
    }
}

Ответ 7

Используйте 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", за исключением спецификации.

Ответ 8

Самый простой способ, которым я нашел обход спецификации

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

Ответ 9

Не уверен, что, по вашему мнению, вы достигаете с tmp.getBytes() и "UTF-8" и т.д.

Я уверен, что Java не поддерживает спецификации, хотя я не могу найти документацию, которая говорит об этом прямо сейчас.

Также стоит отметить, что спецификации в UTF-8 бессмысленны, поскольку стандарт задает порядок байтов независимо от аппаратного обеспечения. Поэтому, если вы можете остановить их создание в первую очередь, это может помочь.