我有一个很大的bigfile.gz.gz
文件。我想在运行中解压缩它。理想情况下,这就是我的想法:
$in = fopen('compress.zlib://compress.zlib://bigfile.gz.gz', 'rb');
while (!feof($in))
print fread($in, 4096);
fclose($in);
但是,compress.zlib://
不能以这种方式链接:
PHP Warning: fopen(): cannot represent a stream of type ZLIB as a File Descriptor in gztest.php on line 1
所以我以为我会将gzopen()
和compress.zlib://
合并在一起:
$in = gzopen('compress.zlib://bigfile.gz.gz', 'rb');
while (!gzeof($in))
print gzread($in, 4096);
gzclose($in);
但是,这只会解压缩一个级别的gzip。
我尝试了其他10种方法,遗憾的是gzopen()
如果使用php://memory
编写了fwrite()
,则无法使用stream_filter_append(… zlib.inflate …)
。并且$in = popen('zcat bigfile.gz.gz | gunzip', 'rb');
while (!feof($in))
print fread($in, 4096);
fclose($in);
无法读取gzip压缩文件。
这是我能想到的最好的,但它会产生两个系统进程,这会产生不良的开销:
{{1}}
有人可以提出更好的建议吗?
答案 0 :(得分:2)
可以使用zlib.inflate过滤器解压缩.gz文件。你只需要先删除gzip头。要动态执行此操作,您必须部署自定义过滤器:
<?php
class gzip_header_filter extends php_user_filter {
private $filtered = 0;
public function filter($in, $out, &$consumed, $closing) {
while ($bucket = stream_bucket_make_writeable($in)) {
if($this->filtered == 0) {
$header_len = 10;
$header = substr($bucket->data, 0, 10);
$flags = ord($header[3]);
if($flags & 0x08) {
// a filename is present
$header_len = strpos($bucket->data, "\0", 10) + 1;
}
$bucket->data = substr($bucket->data, $header_len);
$this->filtered = $header_len;
}
$consumed += $bucket->datalen;
stream_bucket_append($out, $bucket);
}
return PSFS_PASS_ON;
}
}
stream_filter_register('gzip_header_filter', 'gzip_header_filter');
$in = fopen('bigfile.gz.gz', 'rb');
stream_filter_append($in, 'gzip_header_filter', STREAM_FILTER_READ);
stream_filter_append($in, 'zlib.inflate', STREAM_FILTER_READ);
stream_filter_append($in, 'gzip_header_filter', STREAM_FILTER_READ);
stream_filter_append($in, 'zlib.inflate', STREAM_FILTER_READ);
while (!feof($in))
print fread($in, 4096);
fclose($in);
?>
请注意,上面的代码不处理可以存储在gz文件中的注释和其他额外数据。