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

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

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

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

优化前web

优化后算法

本文将介绍 ZIP 流式解压的原理和技术实现路径,但愿为你们带来启发,将 ZIP 流式解压技术更多的应用到业务中。浏览器

一 什么是ZIP缓存

ZIP 是一种文件格式,定义了如何将多个文件、数据块组织在一块儿造成一个完整的文件。例如咱们常见的 .apk,.ipa,.sketch,都是ZIP文件。一般程序是这样建立 ZIP 文件的:网络

压缩单个文件造成单文件数据块;数据结构

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

对每一个待压缩的文件重复以上步骤后,拼接全部数据造成更大的数据块;

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

咱们将文件前部描述信息称为 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

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

戳这里,看该做者更多好文

【编辑推荐】

  1. 全球APP下载最新排名:TikTok继续榜首

  2. 还在嫌弃你的浏览器下载巨慢?教你一招

  3. 经过命令下载执行恶意代码的几种姿式

  4. Windows 10如今仍然能够免费下载安装!附教程

  5. 9 Game被列为最危险的第三方应用下载商店

【责任编辑:武晓燕 TEL:(010)68476606】

本站公众号
   欢迎关注本站公众号,获取更多信息