Двоичные форматы файлов являются наиболее универсальным и компактным средством хранения данных, a QDataStream
позволяет легко получить доступ к двоичным данным. Кроме примеров в данном разделе мы уже видели в главе 4, как QDataStream применяется для чтения и записи файлов в приложении Электронная таблица, и мы снова встретим этот класс в главе 19, где он будет использоваться для чтения и записи файлов курсоров в системе Windows.Чтение и запись текста
Хотя двоичные форматы файлов обычно более компактные, чем текстовые форматы, они плохо воспринимаются человеком и не могут им редактироваться. Там, где последнее играет важную роль, можно использовать текстовые форматы. Qt предоставляет класс QTextStream
для чтения и записи простых текстовых файлов или файлов других текстовых форматов, например HTML, XML, и файлы исходных текстов программ. Работа с XML—файлами рассматривается отдельно в главе 15.QTextStream
обеспечивает преобразование между Unicode и локальной кодировкой системы или любой другой кодировкой и незаметно для пользователя справляется с различными соглашениями относительно окончаний строк, принятыми в разных операционных системах («\r\n» в Windows, «\n» в Unix и Mac OS X). QTextStream использует 16-битовый тип QChar в качестве основного элемента данных. Кроме символов и строк QTextStream поддерживает основные числовые типы С++, преобразуя их в строку и обратно. Например, в следующем фрагменте программного кода выполняется запись строки «Thomas M. Disch: 334\n» в файл sf-book.txt:QFile file("sf-book.txt");
if (!file.open(QIODevice::WriteOnly)) {
cerr << "Cannot open file for writing: "
<< qPrintable(file.errorString) << endl;
return;
}
QTextStream out(&file);
out << "Thomas M. Disch: " << 334 << endl;
Записать текст очень просто, однако его чтение может оказаться трудной задачей, поскольку текстовый формат данных (в отличие от двоичного формата данных, записанных с помощью QDataStream)
в принципе двусмысленный. Давайте рассмотрим следующий пример:out << "Norway" << "Sweden";
Если out является объектом типа QTextStream,
то данные в действительности записываются в виде строки «NorwaySweden». Мы не можем рассчитывать на то, что приведенная ниже строка правильно считает данные:in >> str1 >> str2;
Фактически произойдет то, что строка str1
получит все слово «NorwaySweden», а строка str2 ничего не получит. При использовании класса QDataStream не возникнет таких трудностей, поскольку он сохраняет длину каждой строки в начале символьных данных.Для сложных форматов файлов может потребоваться полнофункциональный парсер. Такой парсер мог бы считывать символ за символом при помощи оператора >>
для типа QChar или строку за строкой при помощи функции QTextStream::readLine. В конце этого раздела мы представим два небольших примера, в одном из которых входной файл считывается построчно, а в другом он считывается посимвольно. Для того чтобы использовать парсеры, работающие с целым текстом, мы могли бы считать весь файл за один шаг, используя функцию QTextStream::readAll, если бы нас не волновал расход памяти или если бы мы знали, что файл будет небольшим.По умолчанию QTextStream
использует локальную кодировку системы (например, ISO 8859-1 или ISO 8859-15 в Америке и в большей части Европы) при чтении и записи. Это можно изменить, используя функцию setCodec:stream.setCodec("UTF-8");
В этом примере используется кодировка UTF-8,
совместимая с популярной кодировкой ASCII и позволяющая представить весь набор символов Unicode. Дополнительная информация о кодировке Unicode и о поддержке кодировок классом QTextStream приводится в главе 17 («Интернационализация»).QTextStream
имеет различные опции, аналогичные опциям . Установить опции можно путем передачи в поток специальных объектов — манипуляторов потока. В следующем примере устанавливаются опции showbase, uppercasedigits и hex перед выводом целого числа 12345678, и в результате получается текст «0xBC614E»:out << showbase << uppercasedigits << hex << 12345678;
Ниже перечислены функции, устанавливающие опции для QTextStream
(рис. 12.1):• setIntegerBase(int):
0 —
основание обнаруживается автоматически по префиксу (при чтении),2 —
двоичное представление,8 —
восьмеричное представление,10 —
десятичное представление,16 —
шестнадцатеричное представление.• setNumberFlags(NumberFlags):