UTF-8 и UTF-16 в Java

Я действительно ожидаю, что байтовые данные ниже должны отображаться по-разному, но на самом деле они одинаковы, согласно wiki http://en.wikipedia.org/wiki/UTF-8#Examples, кодировка в байте выглядит по-другому, но почему Java распечатывает их как то же самое?

    String a = "€";
    byte[] utf16 = a.getBytes(); //Java default UTF-16
    byte[] utf8 = null;

    try {
        utf8 = a.getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        throw new RuntimeException(e);
    }

    for (int i = 0 ; i < utf16.length ; i ++){
        System.out.println("utf16 = " + utf16[i]);
    }

    for (int i = 0 ; i < utf8.length ; i ++){
        System.out.println("utf8 = " + utf8[i]);
    }

4 ответов


хотя Java содержит символы внутри как UTF-16, при преобразовании в байты с помощью String.getBytes(), каждый символ преобразуется с использованием кодировки платформы по умолчанию, которая, вероятно, будет чем-то вроде windows-1252. Результаты, которые я получаю:

utf16 = -30
utf16 = -126
utf16 = -84
utf8 = -30
utf8 = -126
utf8 = -84

это означает, что кодировка по умолчанию - "UTF-8" в моей системе.

также обратите внимание, что документация для String.getBytes () имеет этот комментарий: The behavior of this method when this string cannot be encoded in the default charset is unspecified.

в целом, хотя, вы избежите путаницы, если вы всегда указываете кодировку, как вы делаете с a.getBytes("UTF-8")

кроме того, еще одна вещь, которая может вызвать путаницу, включает символы Unicode непосредственно в исходный файл: String a = "€";. Этот символ евро должен быть закодирован для хранения в виде одного или нескольких байтов в файле. Когда Java компилирует вашу программу, она видит эти байты и декодирует их обратно в символ евро. Ты надеешься. Вы должны быть уверены, что программное обеспечение, которое сохраняет символ евро в файл (Блокнот, eclipse и т. д.) кодирует его так же, как Java ожидает, когда он читает его обратно. UTF-8 становится все более популярным, но он не является универсальным, и многие редакторы не будут писать файлы в UTF-8.


одно любопытство, мне интересно, как JVM знает исходную кодировку по умолчанию ...

механизм, который JVM использует для определения начальной кодировки по умолчанию, специфичен для платформы. В UNIX / UNIX-подобных системах он определяется переменными среды LANG и LC_*; см. man locale.


Ermmm.. Эта команда используется для проверки того, что такое кодировка по умолчанию в конкретной ОС?

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

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

Что делать, если у меня есть исходный файл 10 Java, половина из них сохраняется как UTF-8, а остальные сохраняют как UTF-16, после компиляции я перемещаю их (файл класса) в другую платформу ОС, теперь как JVM знает их кодировку по умолчанию? Будет ли информация о кодировке по умолчанию включена в файл класса Java?

Это довольно запутанный набор вопросов:

  1. текстовый файл не имеет набора символов по умолчанию. Он имеет набор символов / кодировку.

  2. нетекстовый файл вообще не имеет кодировки символов. Концепция бессмысленный.

  3. нет 100% надежного способа определить, что такое кодировка символов текстового файла.

  4. Если вы не скажете компилятору java, что такое кодировка файла, он будет считать, что это кодировка платформы по умолчанию. Компилятор не пытается вас переубедить. Если кодировка получена неправильно, компилятор может заметить или даже не заметить вашу ошибку.

  5. байт-код (".класса") файлы двоичные файлы (см. 2).

  6. когда символьные и строковые литералы компилируются в".класс " файл, они теперь представлены таким образом, что не зависит от кодировки платформы по умолчанию, или что-нибудь еще, что вы можете повлиять.

  7. Если вы допустили ошибку с кодировкой исходного файла при компиляции, вы не можете исправить ее на ".класс " уровень файла. Ваш единственный вариант-вернуться и перекомпилировать классы, сообщив компилятору Java правильная кодировка исходного файла.

  8. "что, если, скажем, у меня есть исходный файл 10 Java, половина из них сохраняется как UTF-8, а остальные - как UTF-16".
    Просто не делай этого!

    • не сохраняйте исходные файлы в смеси кодировок. Ты сведешь себя с ума.
    • я не могу ничего хорошего для хранения файлов в UTF-16 вообще ...

Так, я запутался что, хотя люди говорят "зависит от платформы", это связано с исходным файлом?

зависимость от платформы означает, что она потенциально зависит от операционной системы, поставщика JVM и версии, оборудования и т. д.

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

Если это не так, как я могу объяснить явления выше? В любом случае, путаница выше расширяет мой вопрос на "Итак, что произойдет после компиляции исходного файла в файл класса, потому что файл класса может не содержать информацию о кодировке, поэтому теперь результат действительно зависит от "платформы", но не исходного файла больше?"

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

The ".файлы класса " не зависят от платформы. Но если они созданы неправильно, потому что вы не сказали компилятору Java правильную кодировку для исходных файлов, поле ".class " файлы будут содержать неправильные символы.


почему вы имеете в виду :" концепция "набора символов по умолчанию" для отдельного файла бессмысленна"?

Я говорю это, потому что оно верно!

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

но мы можем контролировать, как мы хотим, чтобы текстовый файл хранился правильно? Даже используя Блокнот, есть возможность выбрать между кодировкой.

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

в блокноте есть немного черной магии, чтобы угадать, что такое кодировка символов, когда он читает текстовый файл. В основном, он смотрит на первый несколько байтов файла, чтобы увидеть, начинается ли он с метки порядка байтов UTF-16. Если он видит один, он может эвристически различать UTF-16, UTF-8 (генерируемый продуктом Microscoft) и "другой". Но он не может различать различные" другие " кодировки символов и не распознает как UTF-8 файл, который не начинается с маркера спецификации. (Спецификация в файле UTF-8-это соглашение, специфичное для Microsoft ... и вызывает проблемы, если приложение Java читает файл и не знает пропустить символ BOM.)

в любом случае, проблемы не в написании исходного файла. Они происходят, когда компилятор Java считывает исходный файл с неправильной кодировкой символов.


вы работаете с плохой гипотеза. The getBytes() метод не использует кодировку UTF-16. Он использует кодировку платформы по умолчанию.

Вы можете запросить его с java.nio.charset.Charset.defaultCharset() метод. В моем случае это UTF-8 и должно быть то же самое для вас.


по умолчанию является либо UTF-8 илиISO-8859-1 Если кодировка платформы не найдена. Не UTF-16. Таким образом, в конечном итоге вы делаете преобразование байтов в UTF-8 только. Вот почему byte[] матч Вы можете найти кодировку по умолчанию, используя

 System.out.println(Charset.defaultCharset().name());