Читаем QT 4: программирование GUI на С++ полностью

Если файл использует формат с собственным номером версии, мы можем его использовать для определения номера версии потока, а не хранить этот номер в явном виде. Предположим, что файл сформирован в формате версии 1.3 нашего приложения. Тогда мы могли бы записать данные следующим образом:

QDataStream out(&file);

out.setVersion(QDataStream::Qt_4_1);

out << quint32(MagicNumber) << quint16(0x0103);

При считывании данных мы определяем версию QDataStream на основе номера версии приложения:

01 QDataStream in(&file);

02 in >> magic >> appVersion;

03 if (magic != MagicNumber) {

04 cerr << "File is not recognized by this application" << endl;

05 return false;

06 } else if (appVersion > 0x0103) {

07 cerr << "File is from a more recent version of the application"

08 << endl;

09 return false;

10 }

11 if (appVersion < 0x0103) {

12 in.setVersion(QDataStream::Qt_3_0);

13 } else {

14 in.setVersion(QDataStream::Qt_4_1);

15 }

В этом примере мы говорим, что для любого файла, сохраненного в приложении с версией меньшей, чем 1.3, используется версия 4 потока данных (Qt_3_0), а для файлов, сохраненных в приложении с версией 1.3, используется версия 7 потока данных (Qt_4_1).

Итак, существует три политики работы с версиями потоков данных QDataStream: жесткое кодирование номера версии, запись и чтение номера версии в явном виде и использование различных жестко закодированных номеров версий в зависимости от версии приложения. Можно применять любую из этих политик для гарантирования чтения данных новой версией приложения, записанных в старой версии, даже если сборка новой версии приложения выполняется с более свежей версией Qt. После выбора политики обработки версий QDataStream чтение и запись двоичных данных в Qt становятся простыми и надежными.

Если мы хотим выполнить чтение или запись за один шаг, мы не должны использовать QDataStream, а вместо этого мы должны вызывать функции write и readAll класса QIODevice. Например:

01 bool copyFile(const QString &source, const QString &dest)

02 {

03 QFile sourceFile(source);

04 if (!sourceFile.open(QIODevice::ReadOnly))

05 return false;

06 QFile destFile(dest);

07 if (!destFile.open(QIODevice::WriteOnly))

08 return false;

09 destFile.write(sourceFile.readAll);

10 return sourceFile.error == QFile::NoError

11 && destFile.error == QFile::NoError;

12 }

В строке, где вызывается readAll, все содержимое входного файла считывается в QByteArray, который затем передается функции write для записи в выходной файл. Хранение всех данных в QByteArray ведет к большему расходу памяти, чем при последовательном чтении элементов, однако это дает некоторые преимущества. Например, мы можем затем использовать функции qCompress и qUncompress для упаковки и распаковки данных.

Существуют другие сценарии, когда прямой доступ к QIODevice оказывается более подходящим, чем использование QDataStream. Класс QIODevice имеет функцию peek, которая возвращает следующие байты данных, перемещая позицию устройства, а также функцию ungetChar, которая возвращает считанный байт в поток. Эти функции работают как на устройствах произвольного доступа (таких, как файлы), так и на последовательных устройствах (таких, как сетевые сокеты). Имеется также функция seek, которая используется для установки позиции устройств, поддерживающих произвольный доступ.

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже