ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js は圧縮と解凍を実装します

Node.js は圧縮と解凍を実装します

小云云
小云云オリジナル
2018-02-22 09:46:032251ブラウズ

圧縮形式

zip と gzip は、私たちが目にする 2 つの最も一般的な圧縮形式です。もちろん、Windows では gzip が使用されることはほとんどありません。 Tar は、デフォルトでは圧縮されないアーカイブ形式で、最終的な tar ファイルを gzip 形式の tar.gz ファイルに圧縮するには、gzip と組み合わせる必要があります。通常、これは tgz と省略されます。

なぜ rar について言及されていないのですか?これは特許で保護されたアルゴリズムであるため、解凍ツールは無料で入手できますが、圧縮ツールは有料です。したがって、一般的なアプリケーション シナリオでは、rar 圧縮ファイルが提供されることはほとんどありません。

この記事では、Node.jsでgzip、tar、tgz、zipを圧縮・解凍する方法をそれぞれ紹介します。

非圧縮ファイル ライブラリ

この記事で使用されている非圧縮ファイル ライブラリは urllib から取得したもので、最初にそれを複製し、指定されたディレクトリに移動する必要があります。

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

gzip

Linux の世界では、各ツールの役割は非常に純粋で単一です。たとえば、gzip はファイルを圧縮するだけであり、フォルダーがどのようにパッケージ化され、圧縮されるかについては何も関係ありません。それはタールです。

ファイルを圧縮する 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 倍以上の圧縮効果が得られました。

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 の世界では、これらの基本的なライブラリがすでに用意されているため、そのまま使用するだけで済みます。

この記事では、圧縮モジュールを使用してすべての圧縮コードと解凍コードを実装します。

なぜ圧縮を選択するのですか?十分なコード品質と単体テストが保証されており、アクティブなメンテナンス状態にあり、非常に使いやすい 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();

ストリームインターフェース

ストリームモードでプログラミングする場合、各ストリームのエラーイベントを処理し、すべてのストリームを手動で破棄する必要があることに注意することが重要です。


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);

ストリームでのバックプレッシャリングに関する公式の推奨事項によると、ポンプ モジュールを使用してストリーム モード プログラミングと連携し、ポンプにこれらのストリームのクリーニング作業を完了させる必要があります。


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 サービスの分野では、HTTP リクエスト自体がリクエスト ストリームであるため、ストリーム モデルの方が大きな利点があります。アップロードされたファイルを 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 Chapter tar がフォルダーのパッケージ化を担当することを事前に知ることができます。

たとえば、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 ストリーム オブジェクトに変換できるため、非常に柔軟です。


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 -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 接口,都有它最合适的场景,你会选择了吗?

到此,你拥有的压缩和解压缩能力,你能够做什么样的服务和功能呢?

相关推荐:

Grunt针对静态文件的压缩,版本控制打包详解

微信小程序图片压缩功能的实现方法

php解压zip压缩包到指定目录实现方法


以上がNode.js は圧縮と解凍を実装しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。