1

我在 Ubuntu 12.04 x86_64 上使用 QuaZIP 0.5.1 和 Qt 5.1.1 for 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 相关的内部内容。

4

3 回答 3

1

没有可靠的方法来确定未压缩流的总大小。有关详细信息和可能的解决方法,请参阅此答案

但是,有一种方法可以在压缩流中获取位置:

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 可以在内部读取和解码比您已经读取的更多的数据。

于 2014-01-13T13:14:06.373 回答
1

在 zlib 1.2.4 及更高版本中,您可以使用该gzoffset()函数获取压缩文件中的当前位置。zlib 的当前版本是 1.2.8。

于 2014-01-13T14:04:54.357 回答
0

对 zlib 使用丑陋的 hack,我能够在压缩流中找到位置。

首先,我将gz_streamgzio.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();
于 2014-01-13T12:43:55.603 回答