Если мы разработали свой собственный формат файлов и собираемся считывать и записывать произвольные символы Unicode, мы можем сохранять данные в кодировке Unicode с помощью вызова
stream.setCodec("UTF-16");
stream.setGenerateByteOrderMark(true);
до начала записи в поток QTextStream. Данные в этом случае будут сохраняться в формате UTF-16, который использует два байта для представления одного символа и который будет иметь префикс из специального 16-битового значения (признак порядка байтов Unicode, 0xFFFE), указывающего на применение файлом кодировки Unicode и на прямой или обратный порядок байтов. Формат UTF-16 идентичен представлению в памяти строк QString, и поэтому чтение и запись представленных в кодировке Unicode строк в формате UTF-16 могут выполняться очень быстро. Однако такой подход связан с перерасходом памяти при сохранении данных, представленных целиком в кодировке ASCII, в формате UTF-16, поскольку в данном случае каждый символ займет два байта вместо одного.
Другие кодировки можно задавать путем вызова функции setCodec() с указанием соответствующего объекта преобразования QTextCodec. QTextCodec осуществляет преобразование между Unicode и заданной кодировкой. Объекты QTextCodec используются в различных контекстах в Qt. Внутренними средствами они применяются для поддержки шрифтов, методов ввода, буфера обмена, технологии «drag-and-drop» и названий файлов. Но мы можем их использовать и непосредственно при написании приложений Qt.
При чтении текстового файла QTextStream автоматически обнаруживает кодировку Unicode, если файл начинается с признака, определяющего порядок байтов. Такой режим работы можно отключить с помощью вызова setAutoDetectUnicode(false). Если нельзя рассчитывать на то, что данные начинаются с признака, определяющего порядок байтов, лучше всего перед чтением вызвать функцию setCodec() с аргументом «UTF-16».
Другой кодировкой, поддерживающей весь Unicode, является UTF-8. Его главное достоинство по сравнению с UTF-16, состоит в том, что он — супермножество по отношению к ASCII. Любой символ с кодом в диапазоне от 0x00 до 0x7F представляется в виде одного байта. Другие символы, включая символы Latin-1, код которых превышает значение 0x7F, представляются в виде последовательности из нескольких байтов. Текст, состоящий в основном из символов ASCII, в формате UTF-8 займет примерно вполовину меньше памяти, чем в формате UTF-16. Для применения UTF-8 с QTextStream перед чтением и записью сделайте вызов setEncoding(QTextStream::UnicodeUTF8).
Если мы всегда собираемся считывать и записывать файлы в кодировке Latin-1, вне зависимости от применяемой пользователем локальной кодировки, мы можем установить кодировку «ISO 8859-1» для потока QTextStream. Например:
QTextStream in(&file);
in.setCodec("ISO 8859-1");
При применении некоторых форматов файлов их кодировка задается в заголовке файла. Заголовок обычно представляется в простом виде в кодировке ASCII, чтобы обеспечить его правильное чтение вне зависимости от используемой кодировки (в предположении, что она является супермножеством по отношению к ASCII). Интересным примером таких форматов являются файлы XML. Обычно файлы XML представлены в кодировке UTF-8 или UTF-16. Для правильного их чтения необходимо вызвать функцию setCodec() с «UTF-8». Если используется формат UTF-16, QTextStream автоматически обнаружит это и настроится на него. Заголовок <?xml?> файла XML иногда содержит аргумент encoding, например:
<?xml version="1.0" encoding="EUC-KR"?>
Поскольку QTextStream не позволяет менять кодировку после начала чтения, чтобы учесть явно заданную кодировку, придется заново прочитать файл, задавая правильное преобразование (полученное функцией QTextCodec::codecForName()). В случае файла XML мы можем сами не делать преобразование кодировок, воспользовавшись классами Qt, предназначенными для XML и описанными в главе 15.
Другое применение объектов QTextCodec заключается в указании кодировки строк в исходном коде. Давайте рассмотрим пример, когда группа японских программистов создает приложение, предназначенное главным образом для применения на японском рынке. Эти программисты, вероятно, будут писать свой исходный программный код в текстовом редакторе, использующем такие кодировки, как EUC-JP или Shift-JIS. Такой редактор позволяет им вводить японские иероглифы непосредственно, и, например, они смогут написать следующий код: