在Node.js跨平台下载和解压缩文件最简单的方法?

只需寻找一个简单的解决scheme,在任何操作系统的Node.js中下载和解压缩.zip.tar.gz文件。

不知道这是内置的,或者我必须使用一个单独的库。 有任何想法吗? 寻找只是几行代码,所以当下一个zip文件来,我想下载节点,这是一个没有道理的。 觉得这应该很容易和/或内置,但我什么都找不到。 谢谢!

结帐adm-zip 。

ADM-ZIP是一个纯粹的JavaScript实现,用于NodeJS的压缩数据压缩。

图书馆允许您:

将zip文件直接解压缩到磁盘或内存缓冲区中压缩文件并以.zip格式或压缩缓冲区将其存储到磁盘更新/从现有.zip中添加新/删除文件的内容

Node通过zlib模块支持gzip和deflate:

 var zlib = require('zlib'); zlib.gunzip(gzipBuffer, function(err, result) { if(err) return console.error(err); console.log(result); }); 

编辑:你甚至可以通过例如Gunzip (使用请求 )直接pipe数据:

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

对于tar档案,有一个Isaacs的tar模块 ,由npm使用。

编辑2:更新了答案,因为zlib不支持zip格式。 这将只适用于gzip

yauzl是一个强大的库解压缩。 devise原则:

  • 按照规范。 不要扫描本地文件头。 读取文件元数据的中央目录。
  • 不要阻塞JavaScript线程。 使用并提供asynchronousAPI。
  • 保持内存使用的控制。 不要尝试一次将全部文件caching在RAM中。
  • 永远不会崩溃(如果正确使用)。 不要让格式不正确的zip文件降低尝试捕获错误的客户端应用程序。
  • 捕获不安全的文件名条目。 如果zip文件条目的文件名以“/”或/ [A-Za-z]://开头,或者包含“..”path段或“\”(根据规范),则会引发错误。

目前有97%的testing覆盖率。

我尝试了几个nodejs解压缩库,包括adm-zip和unzip,然后解决了在yauzl周围的提取zip文件。 看似最简单的实现。

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

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

这是2017年(准确地说是10月26日)。

对于一个古老而普遍的技术,比如解压缩,我期望存在一个相当stream行的,成熟的node.js解压缩库,由于它是“完整的”而“停滞”和“不维护”。

然而,大多数图书馆似乎要么是完全可怕的,要么就在几个月前刚刚出现。 这很关注…所以我已经经历了几个解压缩库,阅读他们的文档,并尝试了他们的例子来试图找出WTF。 例如,我试过这些:

  • 约什沃尔夫/ yauzl
  • antelle / node-stream-zip
  • ZJONSSON / node-unzipper
  • EvanOxfeld / node-unzip
  • Stuk / jszip
  • kriskowal / zip

最佳推荐: yauzl

适用于完全下载的文件。 对stream式传输来说不太好。

有据可查。 效果很好。 说得通。

2nd Pick: node-stream-zip

antelle的node-stream-zip似乎是最好的

安装:

 npm install --save node-stream-zip 

用法:

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

安全警告

不知道这是否会检查entry.name的恶意制作的path将不正确解决(如../../../foo/etc/passwd )。

您可以通过比较/\.\./.test(path.relative('./to/dir', path.resolve('./to/dir', entry.name)))来轻松检查。

优点 :(为什么我认为这是最好的?)

  • 可以解压正常的文件(也许不是一些疯狂的扩展名)
  • 可以stream
  • 似乎不需要加载整个zip来读取条目
  • 在正常的JavaScript(未编译)中有例子
  • 不包括厨房水槽(即url加载,S3或db层)
  • 使用stream行库中的一些现有代码
  • 在代码中没有太多没有道理的时髦或忍者

缺点

  • 吞下像一只饥饿的河马的错误
  • 抛出string而不是错误(没有堆栈跟踪)
  • zip.extract()似乎不工作(因此我在我的例子中使用zip.stream()

亚军:node-unzipper

安装:

 npm install --save unzipper 

用法:

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

优点

  • 似乎以类似于node-stream-zip方式工作,但控制较less
  • 一个更加实用的unzip分支
  • 似乎以串行方式而不是并行方式运行

缺点

  • 厨房水槽很多? 只包括一大堆与解压无关的东西
  • 读取整个文件(通过块,这是很好),而不是随机寻求

我期待了很长时间,没有find简单的工作示例,但基于这些答案,我创build了downloadAndUnzip()函数。

用法很简单:

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

这是宣言:

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

另一个工作例子:

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

我发现以下的成功,使用.zip
(在这里简化张贴:没有错误检查,只是解压所有文件到当前文件夹)

 function DownloadAndUnzip(URL){ var unzip = require('unzip'); var http = require('http'); var request = http.get(URL, function(response) { response.pipe(unzip.Extract({path:'./'})) }); }