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

Java: читатели и кодировки

Java-кодировка по умолчанию - ASCII. Да? (См. Мои изменения ниже)

Когда текстовый файл закодирован в UTF-8? Как читатель знает, что он должен использовать UTF-8?

Читатели, о которых я говорю, следующие:

  • FileReader s
  • BufferedReader от Socket s
  • A Scanner из System.in
  • ...

ИЗМЕНИТЬ

Похоже, что кодировка зависит от ОС, а это означает, что для каждой ОС не выполняется следующее:

'a'== 97
4b9b3361

Ответ 1

Как читатель знает, что ему нужно использовать UTF-8?

Обычно вы указываете в InputStreamReader. Он имеет конструктор с кодировкой символов. Например.

Reader reader = new InputStreamReader(new FileInputStream("c:/foo.txt"), "UTF-8");

Все остальные читатели (насколько мне известно) используют кодировку символов по умолчанию для платформы, которая действительно не может быть правильной кодировкой (например, -cough- CP-1252).

Вы можете теоретически также автоматически определять кодировку символов на основе знака порядка байтов . Это отличает несколько кодировок unicode от других кодировок. Java SE, к сожалению, не имеет API для этого, но вы можете использовать homebrew, который можно использовать для замены InputStreamReader, как в приведенном выше примере:

public class UnicodeReader extends Reader {
    private static final int BOM_SIZE = 4;
    private final InputStreamReader reader;

    /**
     * Construct UnicodeReader
     * @param in Input stream.
     * @param defaultEncoding Default encoding to be used if BOM is not found,
     * or <code>null</code> to use system default encoding.
     * @throws IOException If an I/O error occurs.
     */
    public UnicodeReader(InputStream in, String defaultEncoding) throws IOException {
        byte bom[] = new byte[BOM_SIZE];
        String encoding;
        int unread;
        PushbackInputStream pushbackStream = new PushbackInputStream(in, BOM_SIZE);
        int n = pushbackStream.read(bom, 0, bom.length);

        // Read ahead four bytes and check for BOM marks.
        if ((bom[0] == (byte) 0xEF) && (bom[1] == (byte) 0xBB) && (bom[2] == (byte) 0xBF)) {
            encoding = "UTF-8";
            unread = n - 3;
        } else if ((bom[0] == (byte) 0xFE) && (bom[1] == (byte) 0xFF)) {
            encoding = "UTF-16BE";
            unread = n - 2;
        } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE)) {
            encoding = "UTF-16LE";
            unread = n - 2;
        } else if ((bom[0] == (byte) 0x00) && (bom[1] == (byte) 0x00) && (bom[2] == (byte) 0xFE) && (bom[3] == (byte) 0xFF)) {
            encoding = "UTF-32BE";
            unread = n - 4;
        } else if ((bom[0] == (byte) 0xFF) && (bom[1] == (byte) 0xFE) && (bom[2] == (byte) 0x00) && (bom[3] == (byte) 0x00)) {
            encoding = "UTF-32LE";
            unread = n - 4;
        } else {
            encoding = defaultEncoding;
            unread = n;
        }

        // Unread bytes if necessary and skip BOM marks.
        if (unread > 0) {
            pushbackStream.unread(bom, (n - unread), unread);
        } else if (unread < -1) {
            pushbackStream.unread(bom, 0, 0);
        }

        // Use given encoding.
        if (encoding == null) {
            reader = new InputStreamReader(pushbackStream);
        } else {
            reader = new InputStreamReader(pushbackStream, encoding);
        }
    }

    public String getEncoding() {
        return reader.getEncoding();
    }

    public int read(char[] cbuf, int off, int len) throws IOException {
        return reader.read(cbuf, off, len);
    }

    public void close() throws IOException {
        reader.close();
    }
}

Изменить как ответ на редактирование:

Таким образом, кодировка зависит от ОС. Это значит, что не на каждой ОС это верно:

'a'== 97

Нет, это неправда. Кодировка ASCII (которая содержит 128 символов, 0x00 до 0x7F) - это основа все другие кодировки символов. Только символы, находящиеся за пределами кодировки ASCII, могут быть подвергнуты различной разнице в другой кодировке. Кодировки ISO-8859 охватывают символы в диапазоне ASCII с теми же кодовыми точками. Unicode кодирует символы в диапазоне ISO-8859-1 с теми же кодовыми точками.

Вы можете найти каждый из этих блогов интересным:

Ответ 2

Java-кодировка по умолчанию зависит от вашей ОС. Для Windows это обычно "windows-1252", для Unix обычно это "ISO-8859-1" или "UTF-8".

Читатель знает правильную кодировку, потому что вы говорите правильную кодировку. К сожалению, не все читатели позволяют вам это делать (например, FileReader нет), поэтому часто вам нужно использовать InputStreamReader.

Ответ 3

Для большинства читателей Java использует любые кодировки и символы, установленные вашей платформой - это может быть какой-то вкус ASCII или UTF-8 или что-то более экзотическое, как JIS (в Японии). Символы в этом наборе затем преобразуются в UTF-16, которые Java использует внутри.

Там, где кодирование платформы отличается от кодировки файла (моя проблема - файлы UTF-8 являются стандартными, но моя платформа использует кодировку Windows-1252). Создайте экземпляр InputStreamReader, который использует конструктор, определяющий кодировку.

Изменить: сделайте так:

InputStreamReader myReader = new InputStreamReader(new FileInputStream(myFile),"UTF-8");
//read data
myReader.close();

Однако в IIRC есть некоторые положения, позволяющие автоматически определять общие кодировки (такие как UTF-8 и UTF-16). UTF-16 может быть обнаружен знаком байтового заказа в начале. UTF-8 также следует определенным правилам, но, как правило, разница в ч/б вашей кодировке платформы и UTF-8 не будет иметь значения, если вы не используете международные символы вместо латинских.

Ответ 4

Я хотел бы сначала подходить к этой части:

Java-кодировка по умолчанию - ASCII. Да?

В среде Java есть как минимум 4 разных объекта, которые можно назвать "кодировкой по умолчанию":

  • "набор символов по умолчанию" - это то, что Java использует для преобразования байтов в символы (и byte[] в String) в Runtime, когда ничего не указано. Это зависит от платформы, настроек, аргументов командной строки... и обычно это просто кодировка по умолчанию для платформы.
  • внутренняя кодировка символов, используемая Java в значениях char и String. Этот всегда UTF-16! Невозможно изменить его, это просто UTF-16! Это означает, что char, представляющий a, всегда имеет числовое значение 97, а char, представляющее π, всегда имеет числовое значение 960.
  • кодировка символов, которую использует Java для хранения строковых констант в файлах .class. Этот всегда UTF-8. Невозможно изменить его.
  • кодировка, которую компилятор Java использует для интерпретации исходного кода Java в файлах .java. Этот по умолчанию используется для кодировки по умолчанию, но может быть настроен во время компиляции.

Как читатель знает, что он должен использовать UTF-8?

Это не так. Если у вас есть простой текстовый файл, то вы должны знать кодировку, чтобы прочитать ее правильно. Если вам повезет, вы можете догадаться (например, вы можете попробовать кодировку по умолчанию в платформе), но это процесс, подверженный ошибкам, и во многих случаях у вас даже не будет способа понять, что вы ошиблись. Это не, характерный для Java. Это верно для всех систем.

Некоторые форматы, такие как XML и все форматы на основе XML, были разработаны с учетом этого ограничения и включают способ указания кодировки в данных, чтобы угадать больше не нужно.

Прочитайте Абсолютный минимум Каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Unicode и наборах символов (никаких оправданий!) для деталей.

Ответ 5

Вы можете начать получать эту идею здесь java Charset API

Обратите внимание, что согласно документу

Собственная кодировка символов Язык программирования Java - UTF-16

EDIT:

Извините, мне позвонили, прежде чем я смог закончить это, возможно, мне не следовало бы отправлять частичный ответ так, как есть. Во всяком случае, другие ответы объясняют детали, поскольку основная кодировка файлов для каждой платформы вместе с общими чередующимися кодировками будет корректно считываться java.