使用Node.js实现压缩和解压缩功能
本篇文章主要介绍了基于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 接口,都有它最合适的场景,你会选择了吗?
到此,你拥有的压缩和解压缩能力,你能够做什么样的服务和功能呢?
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
Atas ialah kandungan terperinci 使用Node.js实现压缩和解压缩功能. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Node.js boleh digunakan sebagai rangka kerja bahagian belakang kerana ia menawarkan ciri seperti prestasi tinggi, kebolehskalaan, sokongan merentas platform, ekosistem yang kaya dan kemudahan pembangunan.

Saya mendapati bahawa pakej termampat yang dimuat turun dari laman web muat turun tertentu akan lebih besar daripada pakej termampat asal selepas penyahmampatan Perbezaannya ialah berpuluh-puluh Kb dan berpuluh-puluh Mb jika fail kecil, jika terdapat banyak fail, kos penyimpanan akan meningkat dengan banyak. Saya telah membuat beberapa kajian mengenainya dan boleh belajar daripadanya jika perlu. Tahap mampatan: 9-mampatan melampau Saiz kamus: 256 atau 384, semakin dimampatkan kamus, semakin perlahan perbezaan kadar mampatan lebih besar sebelum 256MB dan tiada perbezaan dalam kadar mampatan selepas 384MB: maksimum 273 Parameter: f=BCJ2, uji dan tambah kadar mampatan parameter akan lebih tinggi

Untuk menyambung ke pangkalan data MySQL, anda perlu mengikuti langkah berikut: Pasang pemacu mysql2. Gunakan mysql2.createConnection() untuk mencipta objek sambungan yang mengandungi alamat hos, port, nama pengguna, kata laluan dan nama pangkalan data. Gunakan connection.query() untuk melaksanakan pertanyaan. Akhir sekali gunakan connection.end() untuk menamatkan sambungan.

Terdapat dua fail berkaitan npm dalam direktori pemasangan Node.js: npm dan npm.cmd Perbezaannya adalah seperti berikut: sambungan berbeza: npm ialah fail boleh laku dan npm.cmd ialah pintasan tetingkap arahan. Pengguna Windows: npm.cmd boleh digunakan daripada command prompt, npm hanya boleh dijalankan dari baris arahan. Keserasian: npm.cmd adalah khusus untuk sistem Windows, npm tersedia merentas platform. Cadangan penggunaan: Pengguna Windows menggunakan npm.cmd, sistem pengendalian lain menggunakan npm.

Pembolehubah global berikut wujud dalam Node.js: Objek global: modul Teras global: proses, konsol, memerlukan pembolehubah persekitaran Runtime: __dirname, __filename, __line, __column Constants: undefined, null, NaN, Infinity, -Infinity

Perbezaan utama antara Node.js dan Java ialah reka bentuk dan ciri: Didorong peristiwa vs. didorong benang: Node.js dipacu peristiwa dan Java dipacu benang. Satu-benang vs. berbilang benang: Node.js menggunakan gelung acara satu-benang dan Java menggunakan seni bina berbilang benang. Persekitaran masa jalan: Node.js berjalan pada enjin JavaScript V8, manakala Java berjalan pada JVM. Sintaks: Node.js menggunakan sintaks JavaScript, manakala Java menggunakan sintaks Java. Tujuan: Node.js sesuai untuk tugas intensif I/O, manakala Java sesuai untuk aplikasi perusahaan besar.

Penjelasan dan Panduan Pemasangan Terperinci untuk Pinetwork Nodes Artikel ini akan memperkenalkan ekosistem pinetwork secara terperinci - nod pi, peranan utama dalam ekosistem pinetwork, dan menyediakan langkah -langkah lengkap untuk pemasangan dan konfigurasi. Selepas pelancaran Rangkaian Ujian Blockchain Pinetwork, nod PI telah menjadi bahagian penting dari banyak perintis yang aktif mengambil bahagian dalam ujian, bersiap sedia untuk pelepasan rangkaian utama yang akan datang. Jika anda tidak tahu kerja pinet, sila rujuk apa itu picoin? Berapakah harga untuk penyenaraian? Penggunaan PI, perlombongan dan analisis keselamatan. Apa itu Pinetwork? Projek Pinetwork bermula pada tahun 2019 dan memiliki syiling pi cryptocurrency eksklusifnya. Projek ini bertujuan untuk mewujudkan satu yang semua orang boleh mengambil bahagian

Ya, Node.js ialah bahasa pembangunan bahagian belakang. Ia digunakan untuk pembangunan bahagian belakang, termasuk mengendalikan logik perniagaan sebelah pelayan, mengurus sambungan pangkalan data dan menyediakan API.
