跨平台下载和解压Node.js中文件的最简单方法?
只是想寻找一个简单的解决方案,在任何操作系统上下载和解压缩Node.js中的跨平台下载和解压Node.js中文件的最简单方法?,node.js,zip,Node.js,Zip,只是想寻找一个简单的解决方案,在任何操作系统上下载和解压缩Node.js中的.zip或.tar.gz文件 不确定这是内置的还是我必须使用单独的库。有什么想法吗?只需要几行代码,所以当下一个zip文件出现时,我想在node中下载它,这是一个很简单的问题。感觉这应该很容易和/或内置,但我找不到任何东西。谢谢 结帐 ADM-ZIP是一个纯JavaScript实现,用于NodeJS的ZIP数据压缩 该库允许您: 将zip文件直接解压缩到磁盘或内存缓冲区中 压缩文件并以.zip格式或压缩缓冲区将其存储到
.zip
或.tar.gz
文件
不确定这是内置的还是我必须使用单独的库。有什么想法吗?只需要几行代码,所以当下一个zip文件出现时,我想在node中下载它,这是一个很简单的问题。感觉这应该很容易和/或内置,但我找不到任何东西。谢谢 结帐
ADM-ZIP是一个纯JavaScript实现,用于NodeJS的ZIP数据压缩
该库允许您:
- 将zip文件直接解压缩到磁盘或内存缓冲区中
- 压缩文件并以
格式或压缩缓冲区将其存储到磁盘.zip
- 更新现有
.zip文件的内容/添加新文件/删除文件
节点内置了对gzip的支持,并通过: 编辑:您甚至可以直接通过
管道数据,例如Gunzip
(使用):
对于tar档案,有一个由npm使用的Isaacs
编辑2:更新答案,因为zlib
不支持zip
格式。这仅适用于gzip
另一个工作示例:
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");
是一个强大的解压库。设计原则:
- 遵循规范。不要扫描本地文件头。读取文件元数据的中心目录
- 不要阻塞JavaScript线程。使用并提供异步API
- 控制内存使用。不要试图一次在RAM中缓冲整个文件
- 切勿碰撞(如果使用正确)。不要让格式错误的zip文件导致试图捕获错误的客户端应用程序宕机
- 捕获不安全的文件名条目。如果zip文件条目的文件名以“/”或“/[A-Za-z]://开头,或包含“.”路径段或“\”(根据规范),则会引发错误
目前有97%的测试覆盖率。我期待了很长一段时间,没有发现简单的工作示例,但基于这些答案,我创建了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);
};
我在以下方面获得了成功,与.zip一起工作
(此处简化发布:无错误检查&只需将所有文件解压缩到当前文件夹)
我尝试了一些nodejs解压库,包括adm-zip和unzip,然后选择了extract-zip,它是yauzl的包装器。似乎是最简单的实现
现在是2017年(确切地说是10月26日)
对于一种古老而普及的技术,比如解压,我希望存在一个相当流行、成熟的node.js解压库,它是“停滞的”和“未维护的”,因为它是“完整的”
然而,大多数库要么看起来非常糟糕,要么最近像几个月前一样有提交。这是相当令人担忧的。。。所以我浏览了几个解压库,阅读了它们的文档,并尝试了它们的示例,试图找出WTF。例如,我尝试了以下方法:
- 约书亚沃尔夫酒店/
- 安特尔/
- 茨琼森/
- 埃文斯菲尔德/
- 斯图克/
- 克里斯科瓦尔/
更新2020:还没有尝试过,但也有
顶级推荐:yauzl
适用于完全下载的文件。不适合流媒体
有据可查。效果很好。有道理
第二个选择:节点流zip
安泰尔的似乎是最好的
安装:
npm install --save node-stream-zip
npm install --save unzipper
用法:
'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));
}
);
});
});
'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()
});
安全警告:
不确定此操作是否会检查entry.name
是否存在恶意创建的路径,这些路径可能无法正确解析(例如。/../../foo
或/etc/passwd
)
您可以通过比较/\.\./.test(path.relative('./to/dir',path.resolve('./to/dir',entry.name))
轻松检查这一点
优点(为什么我认为它是最好的?)
- 可以解压普通文件(可能不是一些具有奇怪扩展名的疯狂文件)
- 能流
- 似乎不必加载整个zip来读取条目
- 有普通JavaScript中的示例(未编译)
- 不包括厨房水槽(即url加载、S3或db层)
- 使用流行库中的一些现有代码
- 代码中没有太多毫无意义的时髦或忍者
缺点:
- 像饥饿的河马一样吞咽错误
- 抛出字符串而不是错误(无堆栈跟踪)
zip.extract()
亚军:节点拉链
安装:
npm install --save node-stream-zip
npm install --save unzipper
用法:
'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));
}
);
});
});
'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()
});
专业人士:
- 似乎以类似于
节点流zip
的方式工作,但控制较少
- 更具功能的
解压叉
- 似乎是串行运行,而不是并行运行
缺点:
- 厨房水槽多少钱?只是包含了大量与解压无关的东西
- 读取整个文件(按块,这很好),而不仅仅是随机查找
您也可以使用“解压”简单地提取现有的zip文件。它适用于任何大小的文件,您需要将其添加为来自的依赖项
fs.createReadStream(filePath).pipe(unzip.Extract({path:moveIntoFolder})).on('close',function(){
//解压后做什么
回调();
});代码>下载并提取.tar.gz
:
const https = require("https");
const tar = require("tar");
https.get("https://url.to/your.tar.gz", function(response) {
response.pipe(
tar.x({
strip: 1,
C: "some-dir"
})
);
});
结帐
不,这两个例子都不起作用。js的zlib模块只用于表示单一资源的流和缓冲区;不是zip或tar档案。你似乎误解了这个问题。他没有试图解压缩单个流或单个文件。他正试图从整个ar中提取文件
import gunzip from 'gunzip-file';
const unzipAll = async () => {
try {
const compFiles = fs.readdirSync('tmp')
await Promise.all(compFiles.map( async file => {
if(file.endsWith(".gz")){
gunzip(`tmp/${file}`, `tmp/${file.slice(0, -3)}`)
}
}));
}
catch(err) {
console.log(err)
}
}