辅助功能*

Adobe

H. Paul Robertson

Adobe
博客*

出版日期:
2008 年 2 月 28 日
用户级别:
中/高级
产品:
Adobe AIR

压缩文件和数据

我们特意将 File Compression Tool 范例应用程序设计得很简单 (见图 1)。该应用程序演示 Adobe AIR 的以下功能:

  • 使用 DEFLATE 压缩算法压缩文件
  • 解压缩以 DEFLATE 压缩算法压缩的文件

File Compression Tool 应用程序

图 1。通过本范例应用程序, 可以压缩和解压缩 GZIP 格式的文件。

注意: 本范例应用程序按原样提供, 用于教学目的。

要求

若要充分利用本篇文章, 您需要以下软件和文件:

Adobe AIR

Adobe Flex Builder 3

范例文件:

本范例应用程序包括以下文件, 这些文件位于 FileCompressionTool 文件夹中:

  • FileCompressionTool.mxml: 应用程序主文件 (Flex 的 MXML 格式), 其中包括本文所讨论的代码
  • CompressScreen.mxml: 定义应用程序的“压缩文件”屏幕的布局和功能的 MXML 文件
  • DecompressScreen.mxml: 定义“解压缩文件”屏幕的布局和功能的 MXML 文件
  • FileCompressionTool-app.xml: AIR 应用程序描述符文件
  • AIR 图标文件范例

注意: 以下这些文件来自 H. Paul Robertson 编写的开源 ActionScript GZIP compression library* (ActionScript GZIP 压缩库)。

  • GZIPEncoder.as: 可用于将文件压缩为 GZIP 压缩格式文件, 或将 GZIP 压缩格式文件解压缩为 ByteArray 或 File 对象的 GZIPEncoder 实例。
  • GZIPFile.as: 代表单个 GZIP 压缩格式文件的 GZIPFile 实例, 其中含有针对各种元数据的属性以及压缩文件中实际的源数据。
  • CRC32Generator.as: CRC32Generator 实例用于生成 CRC-32 值, 该值用于验证从 GZIP 压缩文件中提取的非压缩数据与压缩前的原始内容相比未遭到修改或损坏。CRC-32 检查用于 GZIP 压缩格式中。

必备知识

应具备使用 Flex Builder 构建应用程序的一般经验。有关使用此快速入门指南的详细信息, 请参阅用 Flex 构建快速入门范例应用程序

测试应用程序

下载并安装应用程序安装程序 (FileCompressionTool.air)。从系统的磁盘中选择一个文件, 并使用 GZIP 压缩文件格式将其压缩。然后, 从磁盘中选择一个 GZIP 压缩文件, 将其解压缩, 并将内容保存在本地。

注意: 本应用程序使用 gzip 压缩文件格式, 在 IETF RFC 1952* 中有相关介绍。

了解代码

注意: 对于文件的 MXML 代码所使用的全部 Flex 组件, 本文将不一一介绍。有关详细信息, 请参阅《Flex 3 语言参考》*

了解 gzip 压缩格式

处理 ZIP 或类似文件 (包括本应用程序中使用的 GZIP 文件) 等数据被压缩的文件时, 压缩文件数据并将数据保存在压缩文件中的技术涉及两个方面。

首先, 必须使用某种压缩算法来压缩数据本身, 压缩算法是一组规则, 它定义了一种减少表示文件或数据项所需字节数的方式。 (实现这一点的常用方法是搜索并删除数据中的冗余形式。) DEFLATE 算法就是这样一种用于压缩计算机数据的算法。在 AIR 中, 可以使用 DEFLATE 算法压缩 ByteArray 实例中的数据, 具体做法是调用 ByteArray 实例的 compress() 方法, 为该方法的 algorithm 参数传递常量 CompressionAlgorithm.DEFLATE, 如下所示:

import flash.utils.ByteArray;
import flash.utils.CompressionAlgorithm;
             
var dataToCompress:ByteArray = new ByteArray();
// ... 使用 writeBytes() 或其它方法向 ByteArray 添加数据 ...
             
// 压缩数据
dataToCompress.compress(CompressionAlgorithm.DEFLATE);
// ByteArray 现在包含其原有数据的压缩版本

尽管现在已压缩了数据, 但创建压缩格式文件的过程仅完成了一半。除了包含原始的压缩数据之外, 每种压缩格式 (如 ZIP、GZIP 等) 还在压缩数据文件内存储有关压缩数据的额外信息。每种压缩文件格式的独特之处在于对文件具体构建方式的定义, 其中包括随压缩数据一起存储何种额外信息, 以及如何组织数据与额外信息的捆绑。例如, GZIP 压缩格式规定 GZIP 格式的数据 (例如 GZIP 文件) 除了包含实际的压缩数据之外, 还包含某些指示所使用的压缩格式和压缩算法的标识符、有关压缩执行日期和时间的信息、执行压缩的操作系统等。

如果要编写代码来创建或分析使用特定压缩文件格式构建的文件, 则需要了解 (运行时可以使用 ByteArray.compress()ByteArray.uncompress() 创建或提取的) 实际压缩数据与 (代码将需要创建或读取的) 压缩数据的结构之间的区别。有关如何在 File Compression Tool 范例应用程序中实现这一点的示例, 请参阅用于以 gzip 压缩格式创建文件的 GZIPEncoder.compressToFile() 方法, 以及用于将 gzip 压缩格式文件分解为其各部分的 GZIPEncoder.parseGZIPFile() 方法。

使用 DEFLATE 算法压缩文件

使用 ByteArray.compress() 方法压缩 ByteArray 实例中包含的数据。默认情况下, compress() 方法使用 zlib 压缩格式压缩数据。zlib 类似于 zip 和 gzip, 是一种包括所压缩数据以及关于这些数据的额外信息的压缩格式。如果要使用不同的压缩格式, 如 ZIP 或 GZIP, 则可以通过将 CompressionAlgorithm.DEFLATE 常量作为参数传递给 compress() 方法, 从而指定应仅使用 DEFLATE 算法压缩 ByteArray, 而不添加任何额外信息。GZIPEncoder 类即通过此方式, 在其 compressToFile() 方法中以 gzip 压缩格式压缩文件:

public function compressToFile(src:Object, output:File):void
{
    // ... 执行错误检查 ...
    
    // 此 ByteArray 将包含要压缩的数据
    var srcBytes:ByteArray;
    
    var target:File = new File(output.nativePath);
    
    // ... 用数据填充 srcBytes, 具体取决于来源是
    // File 实例还是 ByteArray 实例 ...
    
    // 打开用于创建结果文件的 FileStream 实例
    var outStream:FileStream = new FileStream();
    outStream.open(target, FileMode.WRITE);
    
    // ... 计算 gzip 格式额外的头部和尾部信息
    // 并将其追加至输出 FileStream ...
    
    // 添加实际的压缩数据
    srcBytes.compress(CompressionAlgorithm.DEFLATE);
    outStream.writeBytes(srcBytes, 0, srcBytes.length);
    
    // ... 将尾部信息追加至输出 FileStream ...
    outStream.close();
}

尽管 compressToFile() 方法在创建输出文件和写入 GZIP 压缩格式所含额外信息的处理过程中略显复杂, 但以下两行代码即可执行压缩数据并将其添加至 GZIP 文件的核心功能:

srcBytes.compress(CompressionAlgorithm.DEFLATE);
outStream.writeBytes(srcBytes, 0, srcBytes.length); 

名为 srcBytes 的 ByteArray 实例包含要压缩的数据 (从用户选择的源文件中加载)。调用 compress() 方法时带有 CompressionAlgorithm.DEFLATE 参数, 因此使用 DEFLATE 压缩算法压缩 srcBytes 中的所有字节。此时, srcBytes 包含数据的压缩版本 (替换了原始内容)。然后将这些数据写入目标文件 (正在创建的 gzip 文件) 中由 gzip 压缩格式指定的相应部分。将整个 srcBytes ByteArray 写入输出文件流时使用 outStream 变量的 writeBytes() 方法 — 三个参数分别指示要写入的数据来自 srcBytes、从 srcBytes 中的位置 0 开始以及一直处理至 srcBytes 的最终位置 (由 srcBytes.length 指示)。

使用 DEFLATE 算法解压缩文件

用户选择要解压缩的 gzip 格式文件后, 该文件将被传递给 GZIPEncoder.uncompressToFile() 方法 (实际上是由该方法对文件进行解压缩), 提取原始的源数据, 并将这些数据写入文件中的指定位置。类似于 compressToFile() 方法, uncompressToFile() 方法也执行若干步骤, 其中主要步骤包括错误检查、隔离 gzip 文件中的额外信息与实际的压缩数据以及确定保存非压缩新数据的文件的名称:

public function uncompressToFile(src:File, output:File):void
{
    // ... 错误检查 ...
    
    // 调用 parseGZIPFile 方法, 该方法将 gzip 文件提取至
    // GZIPFile 实例, 其所含属性代表 gzip 文件的各部分
    var gzipData:GZIPFile = parseGZIPFile(src);
    var outFile:File = new File(output.nativePath);
    
    // ... 确定目标文件路径, 具体取决于
    // 输出是否为目录以及源 gzip 文件是否包含
    // 文件名信息 ...
    
    // 从 gzip 文件中获取实际的压缩字节
    var data:ByteArray = gzipData.getCompressedData();
    
    // 执行解压缩操作
    try
    {
        data.uncompress(CompressionAlgorithm.DEFLATE);
    }
    catch (error:Error)
    {
        throw new IllegalOperationError("The specified file is not a GZIP file.");
    }
    
    // ... 将非压缩数据写入目标文件 ...
}

下面这行代码执行将压缩数据转换为非压缩数据的步骤:

data.uncompress(CompressionAlgorithm.DEFLATE);

调用 uncompress() 方法后, 将解压缩 data ByteArray 实例的压缩内容, data 变量随即包含准备写入目标文件的非压缩数据。

关于作者

H. Paul Robertson 是 Adobe Systems 公司的平台开发人员文档团队的一名 ActionScript 开发人员/文档撰写人员。他曾作为一名 Web 应用程序开发人员与 Russell Chun 共同编写了《Macromedia Flash 8 Advanced: Visual QuickPro Guide》* (Peachpit 出版社, 2005 年)。Paul 是一名 Flash 认证开发人员, 拥有印地安那大学的教学系统技术专业硕士学位。在编写 Web 应用程序、撰写关于 Web 应用程序的稿件、讲授 Web 应用程序课程或更新博客*之余, Paul 喜欢收集各种厨房用具, 并乐于同他的三个孩子在乐高玩具、星球大战游戏等各种重大游艺项目上一争高下。