Maison >interface Web >js tutoriel >Node.js implémente la compression et la décompression

Node.js implémente la compression et la décompression

小云云
小云云original
2018-02-22 09:46:032263parcourir

Formats de compression

zip et gzip sont les deux formats de compression les plus courants que nous voyons. Bien sûr, gzip est rarement exposé sous Windows. Tar est un format d'archive qui ne se compresse pas par défaut. Il doit être combiné avec gzip pour compresser le fichier tar final en un fichier tar.gz au format gzip, généralement abrégé en tgz.

Pourquoi rar n'est-il pas mentionné ? Puisqu'il s'agit d'un algorithme protégé par un brevet, vous pouvez obtenir l'outil de décompression gratuitement, tandis que l'outil de compression doit être payant. Par conséquent, dans nos scénarios d’application généraux, les fichiers compressés rar sont rarement fournis.

Cet article expliquera comment implémenter la compression et la décompression gzip, tar, tgz et zip sous Node.js.

Bibliothèque de fichiers non compressés

La bibliothèque de fichiers non compressés utilisée dans cet article provient de urllib Vous devez d'abord la cloner et accéder au répertoire spécifié.

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

gzip

Dans le monde Linux, les responsabilités de chaque outil seront très pures et très uniques, comme gzip, qui ne compressera que les fichiers. Quant à la façon dont le dossier est empaqueté et compressé, cela n’a rien à voir avec cela. Cela relève de la responsabilité de tar.

Ligne de commande gzip pour compresser un fichier

Par exemple, si nous voulons gzip le fichier nodejs-compressing-demo/lib/urllib.js, nous obtiendrons un fichier urllib.js .gz, le fichier source sera supprimé.


$ 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

La taille du fichier est réduite de 31318 octets à 8909 octets, soit plus de 3,5 fois l'effet de compression.

Vous pouvez également utiliser la méthode pipe, combinée à la commande cat, pour compresser et enregistrer le fichier sous n'importe quel fichier :


$ 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

Implémentation gzip de Node.js

Bien sûr, nous n'implémenterons pas vraiment un algorithme et un outil gzip à partir de zéro. Dans le monde de Node.js, ces bibliothèques de base ont déjà été préparées pour vous. il suffit d'ouvrir la boîte pour l'utiliser.

Cet article utilisera le module de compression pour implémenter tous les codes de compression et de décompression.

Pourquoi choisir la compression ? Parce qu'il offre des garanties suffisantes de qualité de code et de tests unitaires, est dans un état de maintenance active, dispose d'une API très conviviale et prend également en charge les interfaces de streaming.

Interface de promesse


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

Combiné avec le modèle de programmation async/await, le code est écrit comme une io asynchrone ordinaire opération .


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

Interface Stream

Il est important de noter que lors de la programmation en mode Stream, vous devez gérer les erreurs de chaque événement de flux, et tous les flux doivent être détruits manuellement.


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

Selon la recommandation officielle de contre-pression dans les flux, nous devrions utiliser le module de pompe pour coopérer avec la programmation du mode Stream et laisser la pompe terminer le travail de nettoyage de ces flux. .


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

Avantages de l'interface Stream

L'interface Stream semble bien plus compliquée que l'interface Promise, pourquoi y a-t-il une telle chose ? Qu'en est-il des scénarios d'application ?

En fait, dans le domaine des services HTTP, le modèle Stream aura de plus grands avantages, car la requête HTTP elle-même est un Request Stream. Si vous souhaitez renvoyer un fichier téléchargé avec une compression gzip, vous n'en avez pas besoin. pour enregistrer le fichier téléchargé à l'aide de l'interface Stream sur le disque local, mais consommer ce flux de fichiers directement.

En utilisant l'exemple de code pour le téléchargement du fichier egg, nous pouvons implémenter la compression gzip et revenir avec une légère modification.


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

chapitre gzip Vous pouvez savoir à l'avance que tar est responsable de l'emballage du dossier : package :.

Par exemple, si vous souhaitez regrouper l'intégralité du dossier nodejs-compressing-dem o dans un fichier et l'envoyer à d'autres, vous pouvez utiliser la commande 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

Comme vous pouvez le constater, le fichier packagé par tar est généralement plus volumineux car il n'est pas compressé et sa taille est proche de la taille totale réelle du dossier. Nous allons donc tous compresser en même temps que l'emballage.


$ 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

La différence de taille entre tar et tgz est plus de 5 fois, ce qui peut réduire considérablement la bande passante de transmission du réseau.

Node.js implémente tgz

Interface de promesse

Utilisez d'abord compressing.tar.compressDir(sourceDir, targetFile) pour Emballez un dossier dans un fichier tar, puis utilisez la méthode de compression gzip ci-dessus pour compresser le fichier tar dans un fichier 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);
 });

Combiné au modèle de programmation async/wait, le code sera plus facile à lire :


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

Interface de flux

Grâce à la classe compressing.tar.Stream, vous pouvez ajouter dynamiquement n'importe quel fichier et dossier à un objet de flux tar, ce qui est très flexible.


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 peut en fait être considéré comme une combinaison « commerciale » de tar + gzip, qui permet le use Les lecteurs n'ont pas besoin de distinguer s'il s'agit d'un fichier compressé ou d'un dossier compressé, utilisez simplement mon zip de toute façon.

Exemple d'utilisation de l'outil de ligne de commande zip pour compresser un dossier :


$ 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

En comparant les tailles de fichiers de tgz et zip, vous pouvez voir la compression par défaut Sous les paramètres, gzip fonctionnera mieux que zip.

Zip d'implémentation de Node.js

实现代码跟 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压缩包到指定目录实现方法


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn