ZIP 也能边下载边解压?流式解压技术揭秘!

 ​​​​对于一个 ZIP 文件,由于标准的解压方式总是从读取文件的末尾开始的,因此必须下载完整个 ZIP 解压后才能访问。当用户通过网络访问 ZIP 文件时,下载解压所带来的耗时将大大降低用户体验。那么能不能边下载边解压呢?阿里巴巴文娱技术 喻远将介绍 ZIP 流式解压的原理和技术实现路径。

打开网络上的 ZIP 文件需要几步?下载,解压,拿到所有文件。面对一个 ZIP,能不能「边下边播」、「按需下载」?

今年 6 月,优酷绘本技术团队开发出新的解压方式——ZIP 流式解压技术,并成功应用在优酷绘本秒开项目中,30M+ 绘本平均加载时长只需 0.91s,加载耗时比传统的解压方式降低了 88.3%,让用户的阅读体验直线提升。实际对比效果如下:

​​

​​

优化前

​​

​​

优化后

本文将介绍 ZIP 流式解压的原理和技术实现路径,希望为大家带来启发,将 ZIP 流式解压技术更多的应用到业务中。

一 什么是ZIP

ZIP 是一种文件格式,定义了如何将多个文件、数据块组织在一起形成一个完整的文件。例如我们常见的 .apk,.ipa,.sketch,都是ZIP文件。通常程序是这样创建 ZIP 文件的:

压缩单个文件形成单文件数据块;

在数据块前后添加文件描述信息;

对每个待压缩的文件重复以上步骤后,拼接所有数据形成更大的数据块;

提取所有文件描述信息,生成一份「文件目录」,附在最后一个数据块的尾部。

我们将文件前部描述信息称为 Local File Header,文件后部描述信息称为 Data Descriptor, 被压缩的文件本身称为 File Data,将最后的文件目录称为 Central Directory。以上所有合在一起,就是一个标准的 ZIP 文件。如下图:

​​

​​

ZIP 文件格式

一个标准的解压方式总是从读取 ZIP 文件末尾开始的,我们以解压上图的 File Data 1 为例:

​​

​​

首先在 ZIP 文件末尾找到 Central Directory 数据块;

在 Central Directory 数据块中找到 File Header 1;

从 File Header 1 中读取 Local File Header 1 的偏移量和 File Data 1 的相关信息;

根据偏移量找到 Local File Header 1;

读取 Local File Header 1;

解密 File Data 1(如果需要);

解压 File Data 1;

读取 Data Descriptor 1;

使用 File Header 1 中保存的 CRC-32 做校验步骤 7 中计算的 CRC-32,以确保解压后的数据完整性。

标准解压方式存在的不足

可以发现,标准的解压强依赖尾部的 Central Directory。当 ZIP 文件存储在 cdn 上时,哪怕我们只想访问其中的一个文件,也必须下载整个 ZIP 解压后才可访问。假如 ZIP 文件有 100 MB,但是我们只需要访问其中的某一个 10 KB 的文件,那么下载整个 ZIP 将是对流量的巨大浪费。

二 优酷技术方案:ZIP流式解压

我们的一个初步的想法是能不能边下载边解压?

要实现这点,首先需要改变解压方式,使其不能再依赖尾部的 Central Directory。

根据 ZIP 文件格式标准可知,除了 Central Directory,每个 File Data 头部的 Loca File Header 部分也包含了该文件的相关信息。

假如 Local File Header 中包含了充分的信息,我们也许可以基于 Local File Header 去解压文件数据,其解压流程就可以变为:

​​

​​

从头开始,搜索到 Local File Header 1;

读取 Local File Header 1;

解密 File Data 1(如果需要);

解压 File Data 1;

读取 Data Descriptor 1;

CRC32 的校验。

那么 Local File Header 里到底存储了什么?是否满足解密解压所需?

了解 Local File Header

我们根据文档对 Local File Header 的描述,画出其二进制文件中的排列:

​​

​​

Local File Header 数据结构

其中的关键信息为:

Signature

元数据签名

Compress Method

压缩算法

Compressed Size

压缩后文件大小

Uncompressed Size

压缩前文件大小

CRC-32

文件的循环冗余校验值

File name

文件名

元数据签名是一个 Magic Number,用来标记接下来数据是什么内容。例如 Local File Header 的签名是 0x04034b50,用 char 表示也就是 { 'P', 'K', '3', '4' }。当读取到对应数据签名时,则意味着接下来的数据结构符合对应元数据的定义,需要使用对应规则解析。

Compress Method 指明数据块用何种算法压缩,解压需要使用对应的算法。

Compressed Size 和 UnCompressed Size可以帮助确定文件的结尾地址和 Data Descriptor 的偏移量。这两个 Size 也是文件解密时 HMAC 计算的关键。

有了 Magic Number 作为元数据签名,我们只需要逐字节遍历去匹配这个 Number,就可以找到 Loca File Header,而不再需要依赖尾部的定位信息。而且 Local File Header 中存储的元数据足够我们决定解压算法、计算大小、校验 CRC-32 了。

还有一个问题是,解压缩算法是否支持流式解压缩?是否有特定的上下文依赖?通过了解压缩算法的原理[1],我们知道,所有的压缩算法都是支持从头部开始流式解压的。

而下载方面,文件是以从头到尾连续的方式下载,这又天然地和和从头解压的方式配合,便可以初步实现边下边解!

加密 ZIP 文件的问题

一切都相当顺利,直到遇到了加密后的 ZIP 文件。加密后的 ZIP 文件的 Local File Header 中的关键信息除了签名和文件名以外,其他信息都被隐去,需要去 Central Directory 中读取。

再一次,我们回到了依赖 Central Directory 的状态。

在失去如此多关键信息的情况下能否继续做到流式解压?我们需要先挖掘一下 ZIP 的加密方式。

ZIP 的加密方式

ZIP 文件支持多种加密方式,最常见的是 Traditional PKWARE Encryption 和 AES Encryption 。

Traditional PKWARE Encryption 是 ZIP 自定义的一种基于密码的对称加密方式,每个字节的加密仅和密码有关,加密前后的数据长度不变。这种不依赖上下文的加密方式可以实现我们需要的流式解密。

AES 加密采用的是 CTR 模式。CTR 模式将明文分组,并生成一个计数器。使用密钥对计数器进行加密生成二进制字节流。利用这个字节流和明文进行 XOR 操作进行加密。其解密方式也是一样的。

这种方式也支持流式解密。

​​

​​

两种常用的加密方式都支持流式解密,那么加解密需要的关键信息,在 Local File Header 中是否有存储就成了能否流式解密的关键。

流式解密的关键信息

无论是 Traditional PKWARE Encryption 还是 AES Encryption,在解密时都需要一些除密码之外的关键信息,例如盐值,加密算法的强度等。此外,在 AES 加密的 ZIP 文件中, Local File Header 中的 Compress Method 字段被抹去,这样我们便无法知晓压缩算法,因此无法解压。

至此,问题集中为:

  • Local File Header 中是否有足够的加密所需信息。
  • 加密的 ZIP 文件,是否能在除 Central Directory 以外的位置找到 Compress Method 字段。

Local File Header 中加密相关的信息

ZIP 格式的设计者在设计 ZIP 文件格式的初期就提供了文件拓展能力,一些额外的拓展数据可以存放在 Local File Header 的 Extra Field 中。ZIP AES 加密说明书[2]告诉我们 AES 的相关信息就存放在这里。其关键信息如下:

Signature

Extra Data 签名(0x9901)

AES Encryption strength

AES 加密强度(128或192或256)

Actual compress Method

真正的压缩算法

原来压缩算法被藏到了 Extra Data 中。那么盐值被存放在哪里了?答案是存放在 File Data 的头尾。

​​

​​

综上,我们找到解密所需的所有关键信息,整个流式解密解压的所有技术点都被我们探索完。剩下的便是按原理实现,以及细节的打磨。

三 总结

说了那么多,流式解压究竟有什么价值呢?

由于流式解压实现了边下载边解压,将整个操作的时长从下载 + 解压缩变成了约等于纯下载的时长,直接抹掉了解压的耗时。在 39.1 MB 大小的 ZIP 包下载解压测试中,耗时从 9.08 秒降低至 4.17 秒,有将近 100% 的提速!同时,你可以不必等待整个 ZIP 下载解压完,而是在解压完一小部分数据的时候,就直接展示 UI。用户侧看起来就好像一瞬间就解压完了。

因此,流式解压可以应用在许多时间敏感的操作里,也可以用来优化基于 ZIP 文件的相关业务。例如基于 ZIP 的全局换肤加速、基于 ZIP 的 Web 资源缓存加载的加速等等。前言中的优酷绘本秒开就是基于这一技术实现。

参考

[1]https://houbb.github.io/2018/11/09/althgorim-compress-althgorim-12-zip-02[2]AES Encryption Information: Encryption Specification AE-1 and AE-2https://www.winzip.com/win/en/aes_info.html[3]ZIP File Format Specificationhttps://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.1.TXT[4]AES Coding Tips for Developershttps://www.winzip.com/win/en/aes_tips.html

【本文为专栏作者“阿里巴巴官方技术”原创稿件,转载请联系原作者】

​​戳这里,看该作者更多好文​​

分享文章:ZIP 也能边下载边解压?流式解压技术揭秘!
URL地址:http://www.shufengxianlan.com/qtweb/news19/354369.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联