Flash Player 11.4 ByteArray压缩算法初探

Posted on Jul 27, 2012

Flash Player 11.4 更新中,增加了ByteArray 对LZMA压缩算法的支持,压缩能力明显加强。

ByteArray

“ByteArray 类提供用于优化读取、写入以及处理二进制数据的方法和属性。内存中的数据是一个压缩字节数组(数据类型的最紧凑表示形式),但可以使用标准 [](数组访问)运算符来操作 ByteArray 类的实例。也可以使用与 URLStream 和 Socket 类中的方法相类似的方法将它作为内存中的文件进行读取和写入。”

“此外,还支持 zlib 压缩和解压缩,以及 Action Message Format (AMF) 对象序列化。”

目前压缩/解压缩支持三种算法:CompressionAlgorithm. DEFLATE, CompressionAlgorithm. ZLIB, CompressionAlgorithm.LZMA(Flash Player 11.4)。

压缩算法

DEFLATE

DEFLATE是同时使用了LZ77 算法与哈夫曼编码(Huffman Coding) 的一个无损数据压缩算法。它最初是由Phil Katz为他的PKZIP归档工具第二版所定义的,后来定义在RFC 1951规范中。

RFC:http://www.ietf.org/rfc/rfc1951.txt

哈夫曼编码压缩算法的细节,可以参看这篇文章

ZLIB

deflate 压缩算法用于多种压缩格式,如 zlib、gzip、一些 zip 实现等。在使用这些压缩格式之一压缩数据时,除了存储原始数据的压缩版本之外,压缩格式数据(例如 .zip 文件)还包括元数据信息。举例来说,各种文件格式中包括的元数据的类型有文件名、文件修改日期/时间、原始文件大小、可选的注释、校验和数据等。

例如,在使用 zlib 算法压缩 ByteArray 时,将以特定的格式构建生成的 ByteArray。一些字节包含有关所压缩数据的元数据,而另一些字节包含原始 ByteArray 数据的实际压缩版本。根据 zlib 压缩数据格式规范的定义,这些字节(即包含原始数据的压缩版本的部分)使用 deflate 算法进行压缩。因此,这些字节与对原始 ByteArray 调用 compress( air. CompressionAlgorithm.DEFLATE) 所得的结果相同。但是,compress( air.CompressionAlgorithm.ZLIB) 生成的结果包括额外的元数据,而 compress(CompressionAlgorithm.DEFLATE) 生成的结果只包括原始 ByteArray 数据的压缩版本,没有任何其他内容。

若要使用 deflate 格式以 gzip 或 zip 等特定格式压缩 ByteArray 实例的数据,不能只调用 compress(CompressionAlgorithm.DEFLATE)。必须创建一个按照压缩格式规范构建的 ByteArray,包括相应的元数据以及使用 deflate 格式获取的压缩数据。同样,若要对以 gzip 或 zip 这样的格式压缩的数据进行解码,不能对该数据简单地调用 uncompress(CompressionAlgorithm.DEFLATE)。首先,必须将元数据与压缩数据分离,然后才能使用 deflate 格式对压缩数据进行解压缩。

RFC:http://www.ietf.org/rfc/rfc1950.txt

LZMA

LZMA(Lempel-Ziv-Markov chain -Algorithm的缩写)是2001年以来得到发展的一个数据压缩 算法,它用于7-Zip归档工具中的7z 格式。它使用类似于LZ77的字典编码机制,在一般的情况下压缩率比bzip2为高,用于压缩的字典档案大小可达4GB。

代码示例

private function blackOps(isCompress:Boolean = true):void
{
	try{
		if(!_fileRef || !_fileRef.data)
		{
			Alert.show("上传文件先!");
			return;
		}
 
		if(_bytes)
			_bytes.clear();
		_bytes = new ByteArray();
		_bytes.writeBytes(_fileRef.data);
 
		var algo:String;
		switch(cbxAlgo.selectedIndex)
		{
			case 0:
				algo = CompressionAlgorithm.DEFLATE;
				break;
			case 1:
				algo = CompressionAlgorithm.ZLIB;
				break;
			case 2:
				algo = CompressionAlgorithm.LZMA;
				break;
			default:
				Alert.show("选择压缩算法先!");
				return;
				break;
		}
 
		isCompress?_bytes.compress(algo):_bytes.uncompress(algo);
 
		log("使用压缩算法:" + cbxAlgo.selectedItem.label);
		log( (isCompress?"":"解")+"压缩后字节数:"+_bytes.length);
 
		var fileRef:FileReference = new FileReference();
		fileRef.save(_bytes, (isCompress?"comp_":"unComp_") 
                   + algo + "_" +_fileRef.name);
	}
	catch(e:Error)
	{
		Alert.show(e.message);
	}
}

Demo

Flash Player 11.4+ required

Source: 点击下载

结论

用210KB的电子书txt文件做了简单的测试,ZLIB和DEFLATE相差不大,约67KB,LZMA非常给力,压缩到了58KB。在文件中的存在大量重复数据情况下,LZMA相比另外2种更显优势。但是如解压缩数据时,如果没有采用相应的解压缩算法,ZLIB和DEFLATE解压时都会报“Error #2058: 解压缩数据时出错。”的错误,而LZMA解压不正确的数据时报 “Error #1000: 系统内存不足。”,让人有点意外 :-?。

这次主要使用ByteArray支持的三种压缩算法,并作了简单的比较。可能是因为LZMA比较新,压缩率超过前两种,而实际上ZLIB也是采用DEFLATE压缩算法,但是在压缩过程中加入了额外的元数据,形成了较为完备的数据格式。具体算法没有去深入研究,有点可惜和遗憾。


参考资料

  1. http://zh.wikipedia.org/wiki/DEFLATE
  2. http://zh.wikipedia.org/wiki/Zlib
  3. http://zh.wikipedia.org/wiki/LZMA
  4. http://zh.wikipedia.org/wiki/%E9%9C%8D%E5%A4%AB%E6%9B%BC%E7%BC%96%E7%A0%81
  5. http://coolshell.cn/articles/7459.html
  6. http://help.adobe.com/zh_CN/FlashPlatform/reference/actionscript/3/flash/utils/ByteArray.html
  7. http://www.ietf.org/rfc/rfc1950.txt
  8. http://www.ietf.org/rfc/rfc1951.txt