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】