本篇文章主要介绍了基于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 接口,都有它最合适的场景,你会选择了吗?
到此,你拥有的压缩和解压缩能力,你能够做什么样的服务和功能呢?
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
以上是使用Node.js实现压缩和解压缩功能的详细内容。更多信息请关注PHP中文网其他相关文章!

node、nvm与npm的区别:1、nodejs是项目开发时所需要的代码库,nvm是nodejs版本管理工具,npm是nodejs包管理工具;2、nodejs能够使得javascript能够脱离浏览器运行,nvm能够管理nodejs和npm的版本,npm能够管理nodejs的第三方插件。

Vercel是什么?本篇文章带大家了解一下Vercel,并介绍一下在Vercel中部署 Node 服务的方法,希望对大家有所帮助!

node怎么爬取数据?下面本篇文章给大家分享一个node爬虫实例,聊聊利用node抓取小说章节的方法,希望对大家有所帮助!

node导出模块的两种方式:1、利用exports,该方法可以通过添加属性的方式导出,并且可以导出多个成员;2、利用“module.exports”,该方法可以直接通过为“module.exports”赋值的方式导出模块,只能导出单个成员。

安装node时会自动安装npm;npm是nodejs平台默认的包管理工具,新版本的nodejs已经集成了npm,所以npm会随同nodejs一起安装,安装完成后可以利用“npm -v”命令查看是否安装成功。

node中没有包含dom和bom;bom是指浏览器对象模型,bom是指文档对象模型,而node中采用ecmascript进行编码,并且没有浏览器也没有文档,是JavaScript运行在后端的环境平台,因此node中没有包含dom和bom。

本篇文章带大家聊聊Node.js中的path模块,介绍一下path的常见使用场景、执行机制,以及常用工具函数,希望对大家有所帮助!


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

EditPlus 中文破解版
体积小,语法高亮,不支持代码提示功能

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

Atom编辑器mac版下载
最流行的的开源编辑器