[小菜一碟] 在前端用 JavaScript 搭配 pako 套件實現壓縮及解壓縮

最近專案有一個需求,需求當中的一個小部分是要在網頁上將使用者輸入的內容壓縮起來存檔,之後使用者再開啟這個檔案解壓縮顯示壓縮前的內容在網頁上,仔細想想現在的硬碟空間都那麼大,好像沒有什麼壓縮的必要,但是使用者覺得有必要,那也只好做給他了。

第一件要做的事情當然是看有沒有已經有大大做好的套件,一搜尋就找到 pako 這個套件,它是知名前端壓縮及解壓縮套件 zlib 的移植版本,支援 deflategzip 壓縮演算法,下面我們就來看怎麼使用它。

壓縮

畫面我就簡單拉一下,一個 textarea 輸入框、兩個按鈕分別是 Zip 及 Unzip,以及一個檔案選擇器。

<!DOCTYPE html>
<html lang="zh-TW">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Zip & Unzip</title>
  </head>
  <body>
    <div>Input:</div>
    <div><textarea id="inputText" cols="100" rows="30"></textarea></div>
    <div>
      <button onclick="zip.call(this)">Zip</button>
      <input type="file" id="zippedFile" accept=".gzip" />
      <button onclick="unzip.call(this)">Unzip</button>
    </div>
  </body>
</html>

使用者在輸入框輸入文字後,按下 Zip 按鈕,程式就會將使用者輸入的內容做壓縮,並且跳出一個存檔的對話框請使用者存檔,存檔對話框的部分我引用了 FileSaver.js 這個套件來協助我處理,整個壓縮的程式碼如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.4/pako.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script>
    function zip() {
        var textEncoder = new TextEncoder();

        var byteArray = textEncoder.encode(document.getElementById("inputText").value);

        var zippedContent = pako.gzip(byteArray);

        var blob = new Blob([zippedContent]);

        window.saveAs(blob, "hello_world.gzip");
    }
</script>

我們用 TextEncoder 先將使用者輸入的文字 Encode 成型別為 Uint8Array 的二進位資料,然後丟給 pako 執行 gzip 壓縮,壓縮的結果也是 Unit8Array 的二進位資料,最後用壓縮的結果建立一個 Blob 物件,將這個 Blob 物件及預設檔名丟給 window.saveAs() 當參數就完成了。

解壓縮

解壓縮的部分則是讓使用者用檔案選擇器,選擇已存檔的壓縮檔,按下 Unzip 按鈕之後,程式就會將檔案內容解壓縮並且顯示在輸入框內,程式碼如下:

<script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.4/pako.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script>
    function unzip() {
        var fileReader = new FileReader();

        fileReader.onload = function (e) {
            var zippedContent = new Uint8Array(e.target.result);

            var byteArray = pako.ungzip(zippedContent);

            var textDecoder = new TextDecoder();

            var textContent = textDecoder.decode(byteArray);

            document.getElementById("inputText").value = textContent;
        }

        fileReader.readAsArrayBuffer(document.getElementById("zippedFile").files[0]);
    }
</script>

我們用 FileReader 把壓縮檔讀進來之後,將讀取到的內容建立成 Uint8Array 二進位資料,丟給 pako 執行 ungzip 解壓縮,解壓縮的結果也是 Uint8Array 二進位資料,接著我們建立一個 TextDecoder 物件 Decode 解壓縮的結果就會得到壓縮前的內容,最後我們將內容顯示輸入框內,這就完成了一次壓縮及解壓縮過程。

這次全部在前端處理壓縮及解壓縮也算是難得的經驗,分享給大家,如果有其他在前端處理壓縮及解壓縮經驗的朋友,也請不吝留言分享。

參考資料

C# 指南ASP.NET 教學ASP.NET MVC 指引
Azure SQL Database 教學SQL Server 教學Xamarin.Forms 教學