我正在尝试使用PHP来解析在Delphi中创建的自定义gzip存档文件格式(不是我的代码!)。格式基本上是:
4-byte integer: count of files in archive
for each compressed file:
4-byte integer: filename length [n]
[n] bytes: filename
4-byte integer: uncompressed file length [m]
[????] bytes: gzipped content
在我知道长度([m])之后,我可以通过使用zlib_decode()在文件的其余部分上具有最大未压缩长度[m]字节的gzopen()读取文件并实际解码第一个压缩文件,但后来我被卡住了,因为我不知道我应该去找下一个文件名的子字符串多远 - zlib_decode()不会返回它在停止之前处理的压缩字节数。由于这是一种自定义格式,似乎我不能使用普通的gzread() / {{3}}函数,因为整个文件没有压缩(我试过,它不起作用)。< / p>
这段代码在Delphi中工作,因为显然你可以在普通文件读取函数和System.ZLib解码函数之间来回传递文件句柄 - 你可以读取[m]未压缩字节,指针将保留在最后一次压缩byte - 但PHP似乎不支持在正常情况下在read-as-normal和read-as-gzip之间切换。
我是否错过了在PHP中处理这样的混合内容文件格式的明显方法,其中元数据和压缩数据以这种方式堆叠在一起?或者我在不知道压缩数据长度的情况下运气不好?
答案 0 :(得分:0)
一个肮脏的解决方法是重新压缩每个文件的内容,因为我能够解析它,使用它来计算压缩长度,并手动调整原始文件中的文件指针,如下所示:
$current_pos = ftell($handle);
$skip_length = strlen(gzencode($uncompressed_text,9,FORCE_DEFLATE));
fseek($handle, $skip_length+$current_pos);
这有效,但感觉非常黑客。我仍然对任何更好的方法持开放态度。
编辑:
请注意,这最终失败了。但是,我很幸运能够提前知道预期文件名列表,并且我能够执行以下操作(更可靠,因为zlib_decode()会尽可能地解码并丢弃其余的文件名):
foreach ($filenames as $thisFilename) {
$thisPos = strpos($rawData, $thisFilename);
$gzresult = zlib_decode(substr($rawData, $thisPos + strlen($table) + 8)); // skip 8 bytes for filename size and uncompressed data size, which are useless info.
}