繁体   English   中英

使用gzwrite(zlib)知道当前的压缩文件大小

[英]Knowing current compressed file size using gzwrite (zlib)

我正在使用zlib for c ++。

引用http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/zlib-gzwrite-1.html中有关gzwrite函数的报价:

gzwrite()函数应将数据写入到file引用的压缩文件中,该file应以写模式打开(请参见gzopen()gzdopen() )。 进入时, buf应指向包含len个字节的未压缩数据的缓冲区。 gzwrite()函数应压缩该数据并将其写入文件。 gzwrite()函数应返回实际写入的未压缩字节数。

我将其解释为返回值不会告诉我写入时文件变得多大了。 仅将多少数据压缩到文件中。

知道文件的大小的唯一方法是将其关闭,然后从文件系统读取大小。 我要求仅继续写入文件,直到达到一定大小为止。 是否可以在不关闭文件的情况下实现?

一种解决方法是写入,直到未压缩的大小达到我的限制,然后关闭文件,从文件系统读取大小,然后基于此更新对文件大小的最佳猜测,然后重新打开文件并继续写入。 这将使我关闭文件并在最后将文件打开几次(当我接近大小限制时)。

另一个解决方法(可以提供更多的估算值(这并不是我真正想要的))是写入直到未压缩的大小达到限制,然后关闭文件,从文件系统读取文件大小并计算出到目前为止的压缩率。 我可以使用此压缩率来计算未压缩文件大小的新限制,其中压缩应使我降至已压缩文件大小的限制。 如果我再重复一次,估计会有所提高,但同样,不是我想要的。

有更好的选择吗?

首选选项是zlib可以告诉我压缩文件的大小,而文件仍处于打开状态。 我不明白为什么此时此信息在zlib内不可用,因为压缩是在调用gzwrite时发生的,而不是在关闭文件时发生的。

zlib提供了功能gzoffset() ,它可以完全满足您的要求。

如果由于某种原因,您坚持使用的zlib版本已有大约八年的历史,那么在添加gzoffset()时,使用gzdopen()轻松实现。 您可以使用fopen()open()打开输出文件,并提供文件描述符(如果使用fopen() ),则使用fileno()dup() fopen() ),然后将该描述符提供给gzdopen() 然后,您可以随时使用ftell()lseek()查看写入的内容。 请注意不要尝试双重关闭描述符。 请参阅gzdopen()的注释。

您可以通过使用管道来解决此问题。 这个想法是将压缩数据写入管道。 之后,您从管道的另一端读取数据,对其进行计数并将其写入实际文件。

要进行此设置,您需要首先打开文件以通过简单的open写入。 然后通过pipe2创建管道,并通过将管道描述符之一传递给gzdopen来初始化zlib:

int out = open("/path/to/file", O_WRONLY | O_CREAT | O_TRUNC);
int p[2];
pipe2(p, O_NONBLOCK);
gzFile zFile = gzdopen(p[0], "w");

现在,您可以先将数据写入管道,然后将其从管道拼接到out文件:

gzwrite(zFile, buf, 1024); //or any other length
size_t bytesWritten = 0;
do {
    bytesWritten = splice(p[1], NULL, out, NULL, 1024, SPLICE_F_NONBLOCK | SPLICE_F_MORE);
} while(bytesWritten == 1024);

如您所见,您现在拥有bytesWritten来告诉您实际写入了多少数据。 只需将其汇总到另一个变量中,并在写入所需数量的数据后立即停止拼接(或通过将所有内容都写入zFile和拼接一次,并在允许的数据量后一次性拼接)存储为第五个参数,如果您不想压缩不必要的数据,只需按上面的块所示操作即可。

关于splice的注释: Splice是特定 linux的,基本上只是一个非常有效的副本。 你总是可以用一个简单的“读写”组合取代它,即从读取数据fd[1]到缓冲区中,然后写入数据从缓存到out -拼接只是速度更快,更少的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM