首頁 web前端 js教程 使用Node.js實作壓縮和解壓縮功能

使用Node.js實作壓縮和解壓縮功能

Jun 06, 2018 am 09:27 AM
node nodejs 壓縮 解壓縮

本篇文章主要介紹了基於Node.js實作壓縮和解壓縮的方法,現在分享給大家,也給大家做個參考。

壓縮格式

zip 和 gzip 是我們最常看到的兩種壓縮格式,當然,gzip 在 Windows 下很少有人接觸。

tar 是一種歸檔格式,它預設不會壓縮,需要結合 gzip 來將最終的 tar 檔案以 gzip 格式壓縮成為一個 tar.gz 文件,通常我們會縮寫為 tgz。

為什麼沒有提到 rar?因為它是專利保護的演算法,你可以免費獲得解壓縮工具,而壓縮工具是需要付費的。所以我們一般應用場景下,很少會提供 rar 壓縮檔。

本文將分別介紹 gzip,tar,tgz 和 zip 的壓縮和解壓縮在 Node.js 下如何實作。

未壓縮檔案庫

本文所使用的未壓縮檔案庫來自於 urllib ,需要先 clone 它下來到指定目錄。

git clone https://github.com/node-modules/urllib.git nodejs-compressing-demo

gzip

#在Linux 的世界,每個工具的職責會很純粹,非常單一,如gzip,它只會對檔案進行壓縮,至於資料夾如何打包壓縮,跟它沒關係,那是tar 要去負責的事情。

gzip 命令列壓縮一個檔案

例如我們要將nodejs-compressing-demo/lib/urllib.js 檔案進行gzip 壓縮,會得到一個urllib.js .gz 文件,來源文件會被刪除。

$ ls -l nodejs-compressing-demo/lib/urllib.js
-rw-r--r-- 1 a a 31318 Feb 12 11:27 nodejs-compressing-demo/lib/urllib.js

$ gzip nodejs-compressing-demo/lib/urllib.js

$ ls -l nodejs-compressing-demo/lib/urllib.js.gz
-rw-r--r-- 1 a a 8909 Feb 12 11:27 nodejs-compressing-demo/lib/urllib.js.gz

# 还原压缩文件
$ gunzip nodejs-compressing-demo/lib/urllib.js.gz
登入後複製

檔案大小從 31318 位元組減少到 8909 位元組,超過 3.5 倍的壓縮效果。

也可以透過pipe 方式,結合cat 指令,將檔案壓縮並儲存為任意檔案:

$ ls -l nodejs-compressing-demo/README.md
-rw-r--r-- 1 a a 13747 Feb 12 11:27 nodejs-compressing-demo/README.md

$ cat nodejs-compressing-demo/README.md | gzip > README.md.gz

$ ls -l README.md.gz
-rw-r--r-- 1 a a 4903 Feb 12 11:50 README.md.gz
登入後複製

Node.js 實作gzip

當然,我們不會真的從零開始實作一個gzip 演算法和工具,在Node.js 的世界,早已有人為你準備好這些基礎函式庫,我們只需要開箱即用。

本文將會使用 compressing 模組,實作所有壓縮和解壓縮程式碼。

為什麼會選擇 compressing?因為它有足夠的程式碼品質和單元測試保證,處於活躍的維護狀態,API 非常友好,而且還支援串流介面。

Promise 介面

const compressing = require('compressing');

// 选择 gzip 格式,然后调用 compressFile 方法
compressing.gzip.compressFile('nodejs-compressing-demo/lib/urllib.js', 'nodejs-compressing-demo/lib/urllib.js.gz')
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });

// 解压缩是反响过程,接口都统一为 uncompress
compressing.gzip.uncompress('nodejs-compressing-demo/lib/urllib.js.gz', 'nodejs-compressing-demo/lib/urllib.js2')
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });
登入後複製

結合 async/await 的程式設計模型,程式碼寫起來就是一個普通的非同步 io 操作。

const compressing = require('compressing');

async function main() {
 try {
  await compressing.gzip.compressFile('nodejs-compressing-demo/lib/urllib.js',
   'nodejs-compressing-demo/lib/urllib.js.gz');
  console.log('success');
 } catch (err) {
  console.error(err);
 }

 // 解压缩
 try {
  await compressing.gzip.uncompress('nodejs-compressing-demo/lib/urllib.js.gz',
   'nodejs-compressing-demo/lib/urllib.js2');
  console.log('success');
 } catch (err) {
  console.error(err);
 }
}

main();
登入後複製

Stream 介面

需要特別注意的是,使用 Stream 模式編程,需要處理每個 stream 的 error 事件,並且要手動銷毀所有 stream 。

fs.createReadStream('nodejs-compressing-demo/lib/urllib.js')
 .on('error', handleError)
 .pipe(new compressing.gzip.FileStream()) // It's a transform stream
 .on('error', handleError)
 .pipe(fs.createWriteStream('nodejs-compressing-demo/lib/urllib.js.gz2'))
 .on('error', handleError);

// 解压缩,就是 pipe 的方向倒转过来
fs.createReadStream('nodejs-compressing-demo/lib/urllib.js.gz2')
 .on('error', handleError)
 .pipe(new compressing.gzip.UncompressStream()) // It's a transform stream
 .on('error', handleError)
 .pipe(fs.createWriteStream('nodejs-compressing-demo/lib/urllib.js3'))
 .on('error', handleError);
登入後複製

根據官方的Backpressuring in Streams 推薦,我們應該使用 pump 模組來配合 Stream 模式編程,由 pump 來完成這些 Stream 的清理工作。

const pump = require('pump');

const source = fs.createReadStream('nodejs-compressing-demo/lib/urllib.js');
const target = fs.createWriteStream('nodejs-compressing-demo/lib/urllib.js.gz2');

pump(source, new compressing.gzip.FileStream(), target, err => {
 if (err) {
  console.error(err);
 } else {
  console.log('success');
 }
});

// 解压缩
pump(fs.createReadStream('nodejs-compressing-demo/lib/urllib.js.gz2'),
  new compressing.gzip.FileStream(),
  fs.createWriteStream('nodejs-compressing-demo/lib/urllib.js3'),
  err => {
 if (err) {
  console.error(err);
 } else {
  console.log('success');
 }
});
登入後複製

Stream 介面的優勢

Stream 介面看起來比 Promise 介面複雜多了,為何還會有這種應用場景?

其實在HTTP 服務領域,Stream 模型會有更大的優勢,因為HTTP 請求本身就是一個Request Stream,如要將一個上傳檔案以gzip 壓縮返回,使用Stream 介面不需要將上傳檔案儲存到本地磁碟,而是直接消費這個檔案流。

使用 egg 檔案上傳的範例程式碼 ,我們稍微改造一下,就能實現 gzip 壓縮然後返回。

const pump = require('pump');

class UploadFormController extends Controller {
 // ... other codes

 async upload() {
  const stream = await this.ctx.getFileStream();
  // 直接将压缩流赋值给 ctx.body,实现边压缩边返回的流式响应
  this.ctx.body = pump(stream, new compressing.gzip.FileStream());
 }
}
登入後複製

tar | gzip > tgz

gzip 章節可以事先知道,tar 是負責對資料夾進行打包:package:的。

例如要對 nodejs-compressing-dem o 整個資料夾打包成一個檔案傳送給別人,可以透過 tar 指令完成。

$ tar -c -f nodejs-compressing-demo.tar nodejs-compressing-demo/

$ ls -l nodejs-compressing-demo.tar
-rw-r--r-- 1 a a 206336 Feb 12 14:01 nodejs-compressing-demo.tar
登入後複製

如大家所見,tar 打包出來的檔案一般都比較大,因為它是未壓縮的,大小跟實際資料夾總大小接近。所以我們都會在打包同時進行壓縮。

$ tar -c -z -f nodejs-compressing-demo.tgz nodejs-compressing-demo/

$ ls -l nodejs-compressing-demo.tgz
-rw-r--r-- 1 a a 39808 Feb 12 14:07 nodejs-compressing-demo.tgz
登入後複製

tar 和 tgz 超過 5 倍大小的差異,可以大幅減少網路傳輸頻寬。

Node.js 實作tgz

Promise 介面

先使用compressing.tar.compressDir(sourceDir, targetFile) 將一個資料夾打包到一個tar 文件,然後使用上文的gzip 壓縮方式,將tar 檔案壓縮為tgz 檔案。

const compressing = require('compressing');

compressing.tar.compressDir('nodejs-compressing-demo', 'nodejs-compressing-demo.tar')
 .then(() => {
  return compressing.gzip.compressFile('nodejs-compressing-demo.tar',
   'nodejs-compressing-demo.tgz');
 });
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });

// 解压缩
compressing.gzip.uncompress('nodejs-compressing-demo.tgz', 'nodejs-compressing-demo.tar')
 .then(() => {
  return compressing.tar.uncompress('nodejs-compressing-demo.tar',
   'nodejs-compressing-demo2');
 });
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });
登入後複製

結合async/await 的程式設計模型,程式碼寫起來會更容易閱讀:

const compressing = require('compressing');

async function main() {
 try {
  await compressing.tar.compressDir('nodejs-compressing-demo',
   'nodejs-compressing-demo.tar');
  await compressing.gzip.compressFile('nodejs-compressing-demo.tar',
   'nodejs-compressing-demo.tgz');
  console.log('success');
 } catch (err) {
  console.error(err);
 }
 
 // 解压缩
 try {
  await compressing.gzip.uncompress('nodejs-compressing-demo.tgz',
   'nodejs-compressing-demo.tar');
  await compressing.tar.uncompress('nodejs-compressing-demo.tar',
   'nodejs-compressing-demo2');
  console.log('success');
 } catch (err) {
  console.error(err);
 }
}

main();
登入後複製

Stream 介面

透過compressing.tar.Stream類,可以動態添加任意文件、資料夾到一個tar stream 物件中,非常靈活。

const tarStream = new compressing.tar.Stream();
// dir
tarStream.addEntry('dir/path/to/compress');
// file
tarStream.addEntry('file/path/to/compress');
// buffer
tarStream.addEntry(buffer);
// stream
tarStream.addEntry(stream);

const destStream = fs.createWriteStream('path/to/destination.tgz');
pump(tarStream, new compressing.gzip.FileStream(), destStream, err => {
 if (err) {
  console.error(err);
 } else {
  console.log('success');
 }
});
登入後複製

zip

zip 其實可以看成是tar gzip 的「商業化」結合,它讓使用者不需要區分是壓縮檔案還是壓縮資料夾,反正用我zip 就對了。

使用 zip 命令列工具壓縮一個資料夾的範例:

$ zip -r nodejs-compressing-demo.zip nodejs-compressing-demo/
 adding: nodejs-compressing-demo/ (stored 0%)
 adding: nodejs-compressing-demo/test/ (stored 0%)
 ...
 adding: nodejs-compressing-demo/.travis.yml (deflated 36%)

$ ls -l nodejs-compressing-demo.*
-rw-r--r-- 1 a a 206336 Feb 12 14:06 nodejs-compressing-demo.tar
-rw-r--r-- 1 a a  39808 Feb 12 14:07 nodejs-compressing-demo.tgz
-rw-r--r-- 1 a a  55484 Feb 12 14:34 nodejs-compressing-demo.zip
登入後複製

透過 tgz 和 zip 檔案大小對比,可以看出預設的壓縮參數下,gzip 的效果會比 zip 好。

Node.js 實作 zip

實作程式碼跟 tar 類似,只不過預設是壓縮的,不需要再加入 gzip 的過程。

const compressing = require('compressing');

compressing.zip.compressDir('nodejs-compressing-demo', 'nodejs-compressing-demo.zip')
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });

// 解压缩
compressing.zip.uncompress('nodejs-compressing-demo.zip', 'nodejs-compressing-demo3')
 .then(() => {
  console.log('success');
 })
 .catch(err => {
  console.error(err);
 });
登入後複製

總結

基於 Node.js 實作的壓縮和解壓縮是否比想像中簡單?感謝 npm 這個巨人,讓我們編程也能擁有像命令列工具一樣簡單的體驗。

無論是 Promise 接口,還是 Stream 接口,都有它最合適的場景,你會選擇了嗎?

到此,你擁有的壓縮和解壓縮能力,你能夠做什麼樣的服務和功能呢?

上面是我整理給大家的,希望今後對大家有幫助。

相關文章:

使用tween.js實現緩動補間動畫演算法

詳細講解React中的refs(詳細教學)

透過JS如何實現文字間歇循環滾動效果

#

以上是使用Node.js實作壓縮和解壓縮功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

nodejs是後端框架嗎 nodejs是後端框架嗎 Apr 21, 2024 am 05:09 AM

Node.js 可作為後端框架使用,因為它提供高效能、可擴展性、跨平台支援、豐富的生態系統和易於開發等功能。

7-zip最大壓縮率設定,7zip如何壓縮到最小 7-zip最大壓縮率設定,7zip如何壓縮到最小 Jun 18, 2024 pm 06:12 PM

發現某下載網站下載的壓縮包,解壓縮後再打包會比原來的壓縮包大一些,小的幾十Kb的差別,大的幾十Mb的差別,如果上傳到雲盤或付費空間,文件少無所謂,文件多的話,大大的增加儲存成本。特意研究了下,有需要的可以藉鏡。壓縮等級:9-極限壓縮字典大小:256或384,字典越壓縮越慢,256MB之前壓縮率差異較大,384MB後壓縮率無差別單字大小:最大273參數:f=BCJ2,測試加參數壓縮率會高一些

nodejs怎麼連接mysql資料庫 nodejs怎麼連接mysql資料庫 Apr 21, 2024 am 06:13 AM

要連接 MySQL 資料庫,需要遵循以下步驟:安裝 mysql2 驅動程式。使用 mysql2.createConnection() 建立連接對象,其中包含主機位址、連接埠、使用者名稱、密碼和資料庫名稱。使用 connection.query() 執行查詢。最後使用 connection.end() 結束連線。

nodejs中的全域變數有哪些 nodejs中的全域變數有哪些 Apr 21, 2024 am 04:54 AM

Node.js 中存在以下全域變數:全域物件:global核心模組:process、console、require執行階段環境變數:__dirname、__filename、__line、__column常數:undefined、null、NaN、Infinity、-Infinity

nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 nodejs安裝目錄裡的npm與npm.cmd檔有什麼差別 Apr 21, 2024 am 05:18 AM

Node.js 安裝目錄中有兩個與 npm 相關的文件:npm 和 npm.cmd,區別如下:擴展名不同:npm 是可執行文件,npm.cmd 是命令視窗快捷方式。 Windows 使用者:npm.cmd 可以在命令提示字元中使用,npm 只能從命令列執行。相容性:npm.cmd 特定於 Windows 系統,npm 跨平台可用。使用建議:Windows 使用者使用 npm.cmd,其他作業系統使用 npm。

Pi Node教學:什麼是Pi節點?如何安裝和設定Pi Node? Pi Node教學:什麼是Pi節點?如何安裝和設定Pi Node? Mar 05, 2025 pm 05:57 PM

PiNetwork節點詳解及安裝指南本文將詳細介紹PiNetwork生態系統中的關鍵角色——Pi節點,並提供安裝和配置的完整步驟。 Pi節點在PiNetwork區塊鏈測試網推出後,成為眾多先鋒積極參與測試的重要環節,為即將到來的主網發布做準備。如果您還不了解PiNetwork,請參考Pi幣是什麼?上市價格多少? Pi用途、挖礦及安全性分析。什麼是PiNetwork? PiNetwork項目始於2019年,擁有其專屬加密貨幣Pi幣。該項目旨在創建一個人人可參與

nodejs和java的差別大嗎 nodejs和java的差別大嗎 Apr 21, 2024 am 06:12 AM

Node.js 和 Java 的主要差異在於設計和特性:事件驅動與執行緒驅動:Node.js 基於事件驅動,Java 基於執行緒驅動。單執行緒與多執行緒:Node.js 使用單執行緒事件循環,Java 使用多執行緒架構。執行時間環境:Node.js 在 V8 JavaScript 引擎上運行,而 Java 在 JVM 上運行。語法:Node.js 使用 JavaScript 語法,而 Java 使用 Java 語法。用途:Node.js 適用於 I/O 密集型任務,而 Java 適用於大型企業應用程式。

nodejs是後端開發語言嗎 nodejs是後端開發語言嗎 Apr 21, 2024 am 05:09 AM

是的,Node.js 是一種後端開發語言。它用於後端開發,包括處理伺服器端業務邏輯、管理資料庫連接和提供 API。

See all articles