我正在将zlib用于c ++。
语录来自
http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/zlib-gzwrite-1.html关于gzwrite
功能:
gzwrite()
函数应将数据写入由file
引用的压缩文件中,该文件应已以写入模式打开(请参见gzopen()
和gzdopen()
)。进入时,buf
指向包含len
个字节的未压缩数据的缓冲区。gzwrite()
函数应压缩该数据并将其写入文件。gzwrite()
函数应返回实际写入的未压缩字节数。
我将其解释为返回值不会告诉我在写入时文件变大了多少。仅压缩了多少数据到文件中。
然后知道文件的大小的唯一方法是将其关闭,然后从文件系统中读取文件的大小。我要求仅继续写入文件,直到达到一定大小为止。是否可以在不关闭文件的情况下实现?
一种解决方法是写入,直到未压缩的大小达到我的限制,然后关闭文件,从文件系统读取大小,然后基于此更新我对文件大小的最佳猜测,然后重新打开文件并继续写入。这将使我关闭文件并在结尾处打开几次(因为我正接近大小限制)。
另一种解决方法,可以给出更多的估计值(这不是我真正想要的),直到未压缩的大小达到限制为止,然后关闭文件,从文件系统读取文件大小并计算压缩率至今。我可以使用此压缩率来计算未压缩文件大小的新限制,其中压缩应使我降至已压缩文件大小的限制。如果我再重复一次,估计会有所改善,但同样,不是我想要的。
还有更好的选择吗?
首选选项是zlib可以告诉我压缩文件的大小,而文件仍处于打开状态。我不明白为什么此时此信息在zlib中不可用,因为压缩是在调用gzwrite时发生的,而不是在关闭文件时发生的。
答案 0 :(得分:2)
zlib提供了功能gzoffset()
,它可以完全满足您的要求。
如果由于某种原因您坚持使用的zlib版本已有大约八年的历史,那么在添加gzoffset()
时,使用gzdopen()
可以轻松实现。您使用fopen()
或open()
打开输出文件,并提供文件描述符(如果使用fileno()
,则使用dup()
和fopen()
),然后提供gzdopen()
的描述符。然后,您可以随时使用ftell()
或lseek()
查看写入的内容。请注意不要尝试双重关闭描述符。请参阅gzdopen()
的注释。
答案 1 :(得分:0)
您可以使用管道解决此问题。这个想法是将压缩数据写入管道。然后,您从管道的另一端读取数据,对其进行计数并将其写入实际文件中。
要进行此设置,您首先需要打开文件以通过简单的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和拼接一次,并在允许的数据量后一次性拼接)存储为第五个参数。如果您不希望压缩不必要的数据,只需按上面的块所示进行操作即可。
有关拼接的说明:拼接是Linux特定的,基本上只是一个非常有效的副本。您始终可以用一个简单的“读写”组合来代替它,即从fd[1]
读取数据到缓冲区,然后从该缓冲区将数据写入out
-拼接速度更快,代码更少。