PHP中用于大文件的分步BZ压缩

6
使用PHP创建bzip2归档数据非常容易,这要归功于其在bzcompress中的实现。在我的当前应用程序中,我不能仅仅将输入文件读入字符串,然后调用bzcompressbzwrite。 PHP文档并没有清楚地说明使用相对较小的数据连续调用bzwrite是否会产生与一次性压缩整个文件相同的结果。我的意思是类似于:
$data = file_get_contents('/path/to/bigfile');
$cdata = bzcompress($data);

我尝试使用下面展示的例程进行分段bzcompression。

function makeBZFile($infile,$outfile)
{
 $fp = fopen($infile,'r');
 $bz = bzopen($outfile,'w');
 while (!feof($fp))     
 {
  $bytes = fread($fp,10240);
  bzwrite($bz,$bytes);
 }
 bzclose($bz);
 fclose($fp);
}

function unmakeBZFile($infile,$outfile)
{
 $bz = bzopen($infile,'r');
 while (!feof($bz))
 {
  $str = bzread($bz,10240);
  file_put_contents($outfile,$str,FILE_APPEND);
 }
}

set_time_limit(1200);
makeBZFile('/tmp/test.rnd','/tmp/test.bz');
unmakeBZFile('/tmp/test.bz','/tmp/btest.rnd'); 

为了测试这段代码,我做了两件事情:

  • 我使用了makeBZFileunmakeBZFile来压缩和解压缩一个SQLite数据库 - 这正是我最终需要做的。
  • 我创建了一个50MB大小,填充了随机数据的文件dd if=/dev/urandom of='/tmp.test.rnd bs=50M count=1

在两种情况下,我执行了diff original.file decompressed.file,发现两者完全相同。

这很好,但我不清楚为什么它能工作。PHP文档说明bzread(bzpointer,length)读取最多length字节的未压缩数据。如果我的代码如下所示,则可以工作,因为我将bzwitebzread的大小强制设置为10240字节。

我看不到的是如何知道获取未压缩数据的lenth字节数。我查看了bzip2文件格式,但我没有发现任何有助于为.bz文件块建立未压缩数据长度的信息。
我怀疑我对此的理解存在一些漏洞,或者我的代码似乎可以正确地逐步压缩仅仅是偶然的。
我非常感谢在这里得到一些解释。
1个回答

3
To understand how the decompression get the length of bytes you have to understand first the compression. It seems that you don't know any thing about compression algorigthim.

BZIP2

BZIP2的关键算法是Burrows Wheeler变换(BWT),它将原始数据转换为适合后续编码的形式。当前版本应用了Huffman编码。压缩算法完全独立于每个块处理数据。块大小可以在1-9(100,000 - 900,000字节)范围内设置。

BZIP2数据结构

压缩字符串的前两个字符以字母'BZ'开始,之后是1个字节的算法使用。此后紧接着是块大小的标识符,对整个文件有效(h1、h2、h3至h9)。该参数表示块大小,单位为1-9(100,000 - 900,000字节)。

根据所选大小,实际原始数据将存储在块中,并将通过CRC32校验和进行单独保护。此外,48位标识符引入了每个块。这种块结构允许部分重建受损的文件。

GZIP/BZIP

Gzip和bzip2在功能上是等效的。 GZIP的一个优点是它可以压缩流,即您无法向后查看的序列。这使其成为http流的官方压缩器。 GZZIP DEFLATE RFC 1951压缩数据格式规范和GUNZIP RFC 1952文件格式规范是已发布的文档。

GIP解释

GZIP Explained


谢谢你的回答。你可能已经注意到,在我的问题中,我提供了一个我在提问之前研究过的BZIP文件格式的链接。你的回答帮助我理解了bzwrite如何逐块写入数据。但是,对于bzread如何读取指定数量的未压缩字节,我还不太清楚。考虑到每个块中的数据压缩程度会有所不同,这并不像想象中那么简单,即“他想要X个字节的未压缩数据,所以让我只获取下一个X/未压缩大小的块”。 - DroidOS
这不是读取未压缩字节的标准公式。首先,Huffman树在内存中被解码,然后根据树来解压缩数据。 - Vineet1982
如果您还需要了解更多信息,请告诉我,或者接受这个答案。 - Vineet1982

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接