Nous recherchons simplement une solution simple pour télécharger et décompresser les fichiers .Zip
ou .tar.gz
dans Node.js, quel que soit le système d'exploitation utilisé.
Je ne sais pas si cela est intégré ou si je dois utiliser une bibliothèque séparée. Des idées? Nous recherchons quelques lignes de code et, dès que le prochain fichier Zip que je souhaite télécharger dans le nœud, c’est une évidence. Sentez-vous comme cela devrait être facile et/ou intégré, mais je ne trouve rien. Merci!
Commander 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écompresser les fichiers Zip directement sur le disque ou les mémoires tampons en mémoire
- compresser les fichiers et les stocker sur le disque au format
.Zip
ou dans des tampons compressés- mettre à jour le contenu de/ajouter de nouveaux/supprimer des fichiers d'un
.Zip
existant
Nous sommes en 2017 (le 26 octobre pour être exact).
Pour une technologie ancienne et omniprésente telle que unzip, je pense qu’il existe une bibliothèque unzip mature et très populaire, node.js, "stagnante" et "non maintenue" car "complète".
Cependant, la plupart des bibliothèques semblent être complètement terribles ou avoir des commissions récemment comme il y a quelques mois. C'est assez préoccupant ... j'ai donc parcouru plusieurs bibliothèques unzip, lu leur documentation et essayé leurs exemples pour essayer de comprendre WTF. Par exemple, j'ai essayé ceux-ci:
yauzl
node-stream-Zip
node-unzipper
node-unzip
jszip
Zip
yauzl
Fonctionne très bien pour le fichier complètement téléchargé. Pas aussi bien pour le streaming.
Bien documenté. Fonctionne bien. Logique.
node-stream-Zip
antelle's node-stream-Zip
semble être le meilleur
Installer:
npm install --save node-stream-Zip
Usage:
'use strict';
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
mkdirp(path.dirname(pathname, function (err) {
stream.pipe(fs.createWriteStream(pathname));
});
});
});
Avertissement de sécurité:
Je ne sais pas si cela vérifie entry.name
pour trouver des chemins mal conçus qui ne seraient pas résolus correctement (tels que ../../../foo
ou /etc/passwd
).
Vous pouvez facilement le vérifier vous-même en comparant /\.\./.test(path.relative('./to/dir', path.resolve('./to/dir', entry.name)))
.
Pros: (Pourquoi je pense que c'est le meilleur?)
Les inconvénients:
Zip.extract()
ne semble pas fonctionner (j'ai donc utilisé Zip.stream()
dans mon exemple)Installer:
npm install --save unzipper
Usage:
'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()
});
Avantages:
node-stream-Zip
, mais avec moins de contrôleunzip
Les inconvénients:
Node a un support intégré pour gzip et deflate via le module zlib :
var zlib = require('zlib');
zlib.gunzip(gzipBuffer, function(err, result) {
if(err) return console.error(err);
console.log(result);
});
Edit: Vous pouvez même pipe
les données directement via, par exemple. Gunzip
(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 tar, il y a le module tar de Isaacs, utilisé par npm.
Edit 2: La réponse mise à jour en tant que zlib
ne prend pas en charge le format Zip
. Cela ne fonctionnera que pour gzip
.
yauzl est une bibliothèque robuste pour la décompression. Principes de conception:
A actuellement une couverture de test de 97%.
J'ai essayé quelques-unes des bibliothèques de décompression de nœuds telles que adm-Zip et unzip, puis j'ai opté pour extract-Zip, qui est une enveloppe autour de yauzl. 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
})
J'avais hâte de voir cela pendant longtemps et je n'ai trouvé aucun exemple de travail simple, mais en me basant sur ces réponses, j'ai créé la fonction downloadAndUnzip()
.
L'utilisation est assez simple:
downloadAndUnzip('http://your-domain.com/archive.Zip', 'yourfile.xml')
.then(function (data) {
console.log(data); // unzipped content of yourfile.xml in root of archive.Zip
})
.catch(function (err) {
console.error(err);
});
Et voici la déclaration:
var AdmZip = require('adm-Zip');
var request = require('request');
var downloadAndUnzip = function (url, fileName) {
/**
* Download a file
*
* @param url
*/
var download = function (url) {
return new Promise(function (resolve, reject) {
request({
url: url,
method: 'GET',
encoding: null
}, function (err, response, body) {
if (err) {
return reject(err);
}
resolve(body);
});
});
};
/**
* Unzip a Buffer
*
* @param buffer
* @returns {Promise}
*/
var unzip = function (buffer) {
return new Promise(function (resolve, reject) {
var resolved = false;
var Zip = new AdmZip(buffer);
var zipEntries = Zip.getEntries(); // an array of ZipEntry records
zipEntries.forEach(function (zipEntry) {
if (zipEntry.entryName == fileName) {
resolved = true;
resolve(zipEntry.getData().toString('utf8'));
}
});
if (!resolved) {
reject(new Error('No file found in archive: ' + fileName));
}
});
};
return download(url)
.then(unzip);
};
J'ai trouvé le succès avec ce qui suit, fonctionne avec .Zip
(Simplifié ici pour la publication: pas d’erreur de vérification et décompressez simplement tous les fichiers dans le dossier actuel)
function DownloadAndUnzip(URL){
var unzip = require('unzip');
var http = require('http');
var request = http.get(URL, function(response) {
response.pipe(unzip.Extract({path:'./'}))
});
}
Un autre exemple de travail:
var zlib = require('zlib');
var tar = require('tar');
var ftp = require('ftp');
var files = [];
var conn = new ftp();
conn.on('connect', function(e)
{
conn.auth(function(e)
{
if (e)
{
throw e;
}
conn.get('/tz/tzdata-latest.tar.gz', function(e, stream)
{
stream.on('success', function()
{
conn.end();
console.log("Processing files ...");
for (var name in files)
{
var file = files[name];
console.log("filename: " + name);
console.log(file);
}
console.log("OK")
});
stream.on('error', function(e)
{
console.log('ERROR during get(): ' + e);
conn.end();
});
console.log("Reading ...");
stream
.pipe(zlib.createGunzip())
.pipe(tar.Parse())
.on("entry", function (e)
{
var filename = e.props["path"];
console.log("filename:" + filename);
if( files[filename] == null )
{
files[filename] = "";
}
e.on("data", function (c)
{
files[filename] += c.toString();
})
});
});
});
})
.connect(21, "ftp.iana.org");