91 votes

Le moyen le plus simple de télécharger et de décompresser des fichiers en Node.js sur plusieurs plates-formes ?

Je cherche une solution simple pour télécharger et décompresser. .zip o .tar.gz dans Node.js sur n'importe quel système d'exploitation.

Je ne sais pas si cela est intégré ou si je dois utiliser une bibliothèque séparée. Avez-vous une idée ? Je cherche juste quelques lignes de code pour qu'au prochain fichier zip que je veux télécharger dans node, ce soit un jeu d'enfant. J'ai l'impression que cela devrait être facile et/ou intégré, mais je ne trouve rien. Merci !

120voto

CoolAJ86 Points 19341

Nous sommes en 2017 (le 26 octobre, pour être exact).

Pour une technologie ancienne et omniprésente comme unzip, je m'attendrais à ce qu'il existe une bibliothèque unzip node.js assez populaire et mature qui soit "stagnante" et "non maintenue" parce qu'elle est "complète".

Cependant, la plupart des bibliothèques semblent soit être complètement terribles, soit avoir fait l'objet de modifications il y a seulement quelques mois. C'est assez inquiétant... j'ai donc passé en revue plusieurs bibliothèques de dézippage, lu leur documentation et essayé leurs exemples pour essayer de comprendre ce qui se passe. Par exemple, j'ai essayé celles-ci :

Mise à jour 2020 : Je ne l'ai pas encore essayé, mais il y a aussi archiveur

Meilleure recommandation : yauzl

Fonctionne très bien pour un fichier entièrement téléchargé. Pas aussi bien pour le streaming.

Bien documenté. Fonctionne bien. C'est logique.

2ème choix : node-stream-zip

d'antelle node-stream-zip semble être le meilleur

Installez :

npm install --save node-stream-zip

Uso:

'use strict';

var fs = require('fs');
var StreamZip = require('node-stream-zip');

var zip = new StreamZip({
  file: './example.zip'
, storeEntries: true
});

zip.on('error', function (err) { console.error('[ERROR]', err); });

zip.on('ready', function () {
  console.log('All entries read: ' + zip.entriesCount);
  //console.log(zip.entries());
});

zip.on('entry', function (entry) {
  var pathname = path.resolve('./temp', entry.name);
  if (/\.\./.test(path.relative('./temp', pathname))) {
      console.warn("[zip warn]: ignoring maliciously crafted paths in zip file:", entry.name);
      return;
  }

  if ('/' === entry.name[entry.name.length - 1]) {
    console.log('[DIR]', entry.name);
    return;
  }

  console.log('[FILE]', entry.name);
  zip.stream(entry.name, function (err, stream) {
    if (err) { console.error('Error:', err.toString()); return; }

    stream.on('error', function (err) { console.log('[ERROR]', err); return; });

    // example: print contents to screen
    //stream.pipe(process.stdout);

    // example: save contents to file
    fs.mkdir(
      path.dirname(pathname),
      { recursive: true },
      function (err) {
        stream.pipe(fs.createWriteStream(pathname));
      }
    );
  });
});

Avertissement de sécurité :

Je ne suis pas sûr que ce soit le cas. entry.name pour les chemins d'accès malveillants qui ne seraient pas résolus correctement (tels que ../../../foo o /etc/passwd ).

Vous pouvez facilement le vérifier vous-même en comparant /\.\./.test(path.relative('./to/dir', path.resolve('./to/dir', entry.name))) .

Pour (Pourquoi est-ce que je pense que c'est le meilleur ?)

  • peut décompresser des fichiers normaux (peut-être pas des fichiers fous avec des extensions bizarres)
  • peut diffuser
  • semble ne pas devoir charger tout le zip pour lire les entrées
  • a des exemples en JavaScript normal (non compilé)
  • n'inclut pas l'évier de cuisine (c'est-à-dire le chargement d'url, S3, ou les couches de db)
  • utilise du code existant d'une bibliothèque populaire
  • n'a pas trop de hipster ou de ninja-foo insensés dans le code

Cons :

  • Les erreurs des hirondelles comme un hippopotame affamé
  • Lance des chaînes au lieu d'erreurs (pas de traces de pile)
  • zip.extract() ne semble pas fonctionner (c'est pourquoi j'ai utilisé l'option zip.stream() dans mon exemple)

Deuxième place : node-unzipper

Installez :

npm install --save unzipper

Uso:

'use strict';

var fs = require('fs');
var unzipper = require('unzipper');

fs.createReadStream('./example.zip')
  .pipe(unzipper.Parse())
  .on('entry', function (entry) {
    var fileName = entry.path;
    var type = entry.type; // 'Directory' or 'File'

    console.log();
    if (/\/$/.test(fileName)) {
      console.log('[DIR]', fileName, type);
      return;
    }

    console.log('[FILE]', fileName, type);

    // TODO: probably also needs the security check

    entry.pipe(process.stdout/*fs.createWriteStream('output/path')*/);
    // NOTE: To ignore use entry.autodrain() instead of entry.pipe()
  });

Pour :

  • Il semble fonctionner de manière similaire à node-stream-zip mais moins de contrôle
  • Une bifurcation plus fonctionnelle de unzip
  • Semble fonctionner en série plutôt qu'en parallèle

Cons :

  • Un évier de cuisine ? Il inclut juste une tonne de choses qui ne sont pas liées à la décompression.
  • Lit l'ensemble du fichier (par morceaux, ce qui est bien), et pas seulement les recherches aléatoires.

42voto

bryanmac Points 22834

Checkout adm-zip .

ADM-ZIP est une implémentation JavaScript pure pour la compression de données zip pour NodeJS.

La bibliothèque vous permet de :

  • décompression des fichiers zip directement sur le disque ou dans des tampons en mémoire
  • compresser les fichiers et les stocker sur le disque en .zip ou dans des tampons compressés
  • mettre à jour le contenu d'un fichier existant, en ajouter un nouveau ou en supprimer un. .zip

36voto

Linus G Thiel Points 18378

Node dispose d'une prise en charge intégrée de gzip et deflate par le biais de la commande module zlib :

var zlib = require('zlib');

zlib.gunzip(gzipBuffer, function(err, result) {
    if(err) return console.error(err);

    console.log(result);
});

Edita: Vous pouvez même pipe les données directement par le biais, par exemple, de Gunzip (en utilisant demande ) :

var request = require('request'),
    zlib = require('zlib'),
    fs = require('fs'),
    out = fs.createWriteStream('out');

// Fetch http://example.com/foo.gz, gunzip it and store the results in 'out'
request('http://example.com/foo.gz').pipe(zlib.createGunzip()).pipe(out);

Pour les archives du goudron, il y a l'Isaacs module tar qui est utilisé par npm.

Edit 2 : Réponse actualisée comme zlib ne prend pas en charge le zip format. Cela ne fonctionnera que pour gzip .

20voto

Simon Hutchison Points 31

J'ai essayé quelques-unes des bibliothèques de décompression de nodejs, dont adm-zip et unzip, puis j'ai opté pour extract-zip qui est une enveloppe de yauzl. Cela semblait le plus simple à mettre en œuvre.

https://www.npmjs.com/package/extract-zip

var extract = require('extract-zip')
extract(zipfile, { dir: outputPath }, function (err) {
   // handle err
})

15voto

superjoe30 Points 6876

yauzl est une bibliothèque robuste pour le dézippage. Principes de conception :

  • Suivez la spécification. Ne cherchez pas les en-têtes des fichiers locaux. Lisez le répertoire central pour les métadonnées des fichiers.
  • Ne bloquez pas le fil JavaScript. Utilisez et fournissez des API asynchrones.
  • Maîtrisez l'utilisation de la mémoire. N'essayez pas de mettre en mémoire tampon des fichiers entiers en même temps.
  • Ne se plantent jamais (si elles sont utilisées correctement). Ne laissez pas les fichiers zip mal formés faire tomber les applications clientes qui tentent de détecter les erreurs.
  • Capture les entrées de noms de fichiers non sécurisées. Une entrée de fichier zip génère une erreur si son nom de fichier commence par "/" ou /[A-Za-z]:// ou s'il contient des segments de chemin ".." ou "\" (selon la spécification).

La couverture des tests est actuellement de 97%.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X