如何报告在QuaGzipFile(QuaZIP库)上读取的数据的进度



我在Ubuntu 12.04 x86_64上使用QuaZIP 0.5.1和Qt 5.1.1作为C++。

我的程序读取一个大的gzip二进制文件,通常是1GB或更多的未压缩数据,并对其进行一些计算。它的计算量不高,大部分时间都在I/O上。所以,如果我能找到一种方法来报告文件中读取了多少数据,我可以在进度条上报告,甚至可以提供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的丑陋破解,我能够在压缩流中找到位置。

首先,我从gzio.c(从zlib-1.2.3.4源代码)中复制了gz_stream的定义,并将其复制到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();

相关内容

  • 没有找到相关文章

最新更新