Я использую QuaZIP 0.5.1 с Qt 5.1.1 для C ++ в Ubuntu 12.04 x86_64.
Моя программа читает большой сжатый двоичный файл, обычно 1 ГБ несжатых данных или более, и выполняет на нем некоторые вычисления. Он не требует больших вычислительных ресурсов и большую часть времени отводится на ввод-вывод. Поэтому, если я могу найти способ сообщить, сколько данных файла прочитано, я могу сообщить об этом на индикаторе выполнения и даже дать оценку ETA.
Я открываю файл с:
QuaGzipFile gzip(fileName);
if (!gzip.open(QIODevice::ReadOnly))
{
// report error
return;
}
Но в QuaGzipFile нет функциональности для определения размера файла или текущей позиции.
Мне не нужно находить размер и положение несжатого потока, размер и положение сжатого потока хороши, потому что достаточно грубой оценки прогресса.
В настоящее время я могу найти размер сжатого файла, с помощью QFile(fileName).size()
, Кроме того, я могу легко найти текущая позиция в несжатом потоке, сохраняя сумму возвращаемых значений gzip.read()
, Но эти два числа не совпадают.
Я могу изменить библиотеку QuaZIP и получить доступ к внутренним материалам, связанным с zlib, если это поможет.
Не существует надежного способа определения общего размера несжатого потока. Увидеть этот ответ для деталей и возможных обходных путей.
Однако есть способ получить позицию в сжатом потоке:
QFile file(fileName);
file.open(QFile::ReadOnly);
QuaGzipFile gzip;
gzip.open(file.handle(), QuaGzipFile::ReadOnly);
while(true) {
QByteArray buf = gzip.read(1000);
//process buf
if (buf.isEmpty()) { break; }
QFile temp_file_object;
temp_file_object.open(file.handle(), QFile::ReadOnly);
double progress = 100.0 * temp_file_object.pos() / file.size();
qDebug() << qRound(progress) << "%";
}
Идея состоит в том, чтобы открыть файл вручную и использовать дескриптор файла, чтобы получить позицию. QFile не может отслеживать внешние изменения позиции, поэтому file.pos()
будет всегда 0. Таким образом, мы создаем temp_file_object
из файлового дескриптора, заставляя QFile запрашивать позицию файла. Я мог бы использовать API более низкого уровня (например, lseek()
), чтобы получить позицию файла, но я думаю, что мой путь более кроссплатформенный.
Обратите внимание, что этот метод не очень точен и может давать значения прогресса больше, чем реальные. Это потому, что zlib может внутренне читать и декодировать больше данных, чем вы уже прочитали.
В zlib 1.2.4 и выше вы можете использовать gzoffset()
функция, чтобы получить текущую позицию в сжатом файле. Текущая версия zlib — 1.2.8.
Используя некрасивый хак к zlib, я смог найти позицию в сжатом потоке.
Во-первых, я скопировал определение gz_stream
от gzio.c (из источника zlib-1.2.3.4) до конца quagzipfile.cpp. Затем я переопределил виртуальную функцию qint64 QIODevice::pos() const
:
qint64 QuaGzipFile::pos() const
{
gz_stream *s = (gz_stream *)d->gzd;
return ftello64(s->file);
}
Поскольку quagzipfile.cpp и quagzipfile.h кажутся независимыми от других библиотечных файлов QuaZIP, может быть, лучше скопировать нужные мне функции из этих файлов и избежать этого взлома?
Текущая версия программы выглядит примерно так:
QFile infile(fileName);
if (!infile.open(QIODevice::ReadOnly))
return;
qint64 fileSize = infile.size;
infile.close();
QuaGzipFile gzip(fileName);
if (!gzip.open(QIODevice::ReadOnly))
return;
qint64 nread;
char buffer[bufferSize];
while ((nread = gzip.read(&buffer, bufferSize)) > 0)
{
// use buffer
int percent = 100.0 * gzip.pos() / fileSize;
// report percent
}
gzip.close();