Как известно, Java использует представление строк в формате Unicode. В этой статье речь пойдет о способах хранения и представления данных, записанных в разных кодировках.
Написать java-апплет, выводящий приветствие на русском языке очень просто. Можно вставить строку с русским языком прямо внутрь текста класса:
String labelName = "Привет!"; JLabel myLabel = new JLabel(labelName);
Однако не факт, что это будет работать. Ведь тот русский текст, который был набран в редакторе, мог существовать практически в любой кодировке (DOS/Win/UNIX). Исходный текст программы обычно представлен в 8-битном формате, а один символ (char) в java занимает 2 байта (это связано с тем, что язык java ориентирован на поддержку и на работу с Unicode). Таким образом при компиляции программы происходит преобразование символов из одной кодировки (кодировки редактора) в другую (Unicode).
Это преобразование (перекодировка) основывается на том, что исходный текст программы написан в той же кодировке, что и базовая кодировка Java Virtual Machine (JVM), которая, как правило, совпадает с кодировкой самой операционной системы (для русских Windows это будет Cp1251). Таким образом, если кодировка кириллицы в редакторе совпала с кодировкой кириллицы в системе, то сообщение ``Привет!'' появится в нормальном виде.
Чтобы избежать путаницы с кодировками русского языка в тексте программы, у компилятора javac есть специальный параметр encoding, который определяет кодировку исходного текста программы.
Есть и другой способ. Русские буквы в тексте программы можно указывать в формате `\uXXXX' (где XXXX -- шестнадцатиричный код символа в стандарте Unicode). В комплект JDK входит утилита native2ascii, которая позволяет перевести текст из любой поддерживаемых JDK кодировок в ASCII-вид, а символы, не имеющие отображения в ASCII, представить в `\uXXXX' виде. Узнать код того или иного символа кириллицы в Unicode можно, запустив программу charmap в WindowsNT.
Как показать русский текст из внешнего источника, например файла? Текст в файле хранится, как правило, в 8-битном формате. Для чтения/записи и преобразования набора байт в строку и обратно используются специальные классы из пакета java.io: InputStreamReader и OutputStreamReader.
Эти два класса специально предназначены для преобразования потока байт в указанной кодировке (чем по умолчанию является кодировка системы) в Unicode строку java.
Вот типичный пример создания "читателя" из файла:
FileInputStream fis = new FileInputStream("priwet.txt"); InputStreamReader isr = new InputStreamReader(fis, "Cp1251"); Reader in = new BufferedReader(isr);
Предположим, однако, что необходимо работать с внешним текстом (или данными) не только в русской, а в любой кодировке. Эту проблему можно решить двумя способами: храня внешние данные в формате Unicode или же в формате MBCS (MultiByte Character Set).
Несмотря на то, что Unicode был специально разработан для поддержки многих языков, использовать его для хранения и передачи строк в Америке и большей части Европы неэффективно, потому что для этих регионов достаточно 256, а иногда всего 128 символов. Ведь первые 128 символов Unicode (\u0000 -- \u007F) совпадают с ISO-646, а первые 256 символов (\u0000 -- \u007F) совпадают с ISO-8859-1. Тем самым, используется только маленький кусочек всего спектра Unicode, ведь старший байт почти всегда равен нулю.
Возникает желание по-прежнему использовать Unicode внутри программы, но хранить и передавать данные в 8-битной кодировке, преобразуя данные непосредственно перед их получением или записью. В качестве записи в 8-битной кодировке можно использовать технологию MBCS, где каждый символ может занимать несколько байт.
Вопрос заключается в том, какой набор символов (кодировку) использовать для такого преобразования. Существующие кодировки не подходили для этой цели, поэтому Unicode Consortium выработал специальные кодировки для преобразования Unicode-строк в MBCS-строки. Эти кодировки носят название Unicode Transformation Format (UTF), и существуют в двух вариантах: UTF-7 и UTF-8. Они различаются количеством бит (7 или 8), используемых для кодирования.
Кодировка UTF-7 характерна тем, что часто требует больше байтов для представления данных, чем сам Unicode. Но эта кодировка необходима, так как многие старые системы (и не только, например, MIME) используют 7-битную кодировку символов.
Кодировка UTF-8, в свою очередь, очень хорошо подходит для хранения текста, который используют ASCII символы, и символы, чей Unicode код меньше \u0800. В этом спектре лежит большинство символов, используемых в европейских (соответственно, и американских) и ближневосточных странах. Для символов, чей код больше \u07FF, UTF-8, наоборот, мало подходит, потому что эти символы расплываются до 3 байт.
Алгоритмы конвертации между Unicode и UTF-7 или UTF-8 описаны в стандарте Unicode (The Unicode Standart).
Чтобы узнать, как будет выглядеть текстовый файл в формате Unicode, можно запустить программу notepad в WindowsNT и при сохранении текстового файла поставить галочку ``Сохранить в формате Unicode''.
Так как каждый символ занимает 2 байта, то возникает проблема, в каком порядке они должны быть записаны. Рассмотрим строку ``Привет!''. Возможны два варианта:
Какой из вариантов является правильным? В стандарте Unicode написано, что порядок байт по умолчанию является либо big endian, либо little endian :-)
Действительно, оба порядка являются правильным, и разработчики систем сами выбирают себе один из них. Так что нечего беспокоиться, если ваша Windows NT Workstation обменивается данными с Windows NT Server -- они обе используют little endian.
Однако, если ваша Windows NT Workstation обменивается данными с UNIX-сервером, который использует big endian, одна из систем должна осуществлять перекодировку. В этом случае стандарт Unicode гласит, что можно выбрать любой из следующих способов решения проблемы: