如何在NodeJs的内存中下载和解压zip文件?

我想从互联网下载一个zip文件,并将其解压缩到内存中,而不保存到临时文件中。 我怎样才能做到这一点?

这是我试过的:

var url = 'http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip'; var request = require('request'), fs = require('fs'), zlib = require('zlib'); request.get(url, function(err, res, file) { if(err) throw err; zlib.unzip(file, function(err, txt) { if(err) throw err; console.log(txt.toString()); //outputs nothing }); }); 

[编辑]作为,build议,我尝试使用adm-zip库,我仍然无法完成这项工作:

 var ZipEntry = require('adm-zip/zipEntry'); request.get(url, function(err, res, zipFile) { if(err) throw err; var zip = new ZipEntry(); zip.setCompressedData(new Buffer(zipFile.toString('utf-8'))); var text = zip.getData(); console.log(text.toString()); // fails }); 
  • 你需要一个可以处理缓冲区的库。 最新版本的adm-zip将会:

    npm install git://github.com/cthackers/adm-zip.git

  • 我的解决scheme使用http.get方法,因为它返回Buffer块。

码:

 var file_url = 'http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip'; var request = require('request'); var fs = require('fs'); var AdmZip = require('adm-zip'); var http = require('http'); var url = require('url'); var options = { host: url.parse(file_url).host, port: 80, path: url.parse(file_url).pathname }; http.get(options, function(res) { var data = [], dataLen = 0; res.on('data', function(chunk) { data.push(chunk); dataLen += chunk.length; }).on('end', function() { var buf = new Buffer(dataLen); for (var i=0, len = data.length, pos = 0; i < len; i++) { data[i].copy(buf, pos); pos += data[i].length; } var zip = new AdmZip(buf); var zipEntries = zip.getEntries(); console.log(zipEntries.length) for (var i = 0; i < zipEntries.length; i++) console.log(zip.readAsText(zipEntries[i])); }); }); 

这个想法是创build一个缓冲区数组,并在最后连接成一个新的缓冲区。 这是因为缓冲区不能resize。

令人遗憾的是,您不能像zlib lib允许的那样将响应stream传送到解压缩作业中,您必须caching并等待响应结束。 我build议你在大文件的情况下将响应传送给一个fsstream,否则你将在一瞬间完全填满你的记忆!

我不完全明白你在做什么,但是这是最好的方法 。 您应该只在您真正需要的时候将数据保存在内存中 ,然后stream式传输到csvparsing器

如果你想保留所有的数据在内存中,你可以用from代替csvparsing器的方法fromPath ,取而代之的是在getData中直接解unzipped

您可以使用AMDZip (如@mihai所说)而不是node-zip ,只需要注意,因为AMDZip尚未发布在npm中,所以您需要:

 $ npm install git://github.com/cthackers/adm-zip.git 

注意假设:压缩文件只包含一个文件

 var request = require('request'), fs = require('fs'), csv = require('csv') NodeZip = require('node-zip') function getData(tmpFolder, url, callback) { var tempZipFilePath = tmpFolder + new Date().getTime() + Math.random() var tempZipFileStream = fs.createWriteStream(tempZipFilePath) request.get({ url: url, encoding: null }).on('end', function() { fs.readFile(tempZipFilePath, 'base64', function (err, zipContent) { var zip = new NodeZip(zipContent, { base64: true }) Object.keys(zip.files).forEach(function (filename) { var tempFilePath = tmpFolder + new Date().getTime() + Math.random() var unzipped = zip.files[filename].data fs.writeFile(tempFilePath, unzipped, function (err) { callback(err, tempFilePath) }) }) }) }).pipe(tempZipFileStream) } getData('/tmp/', 'http://bdn-ak.bloomberg.com/precanned/Comdty_Calendar_Spread_Option_20120428.txt.zip', function (err, path) { if (err) { return console.error('error: %s' + err.message) } var metadata = [] csv().fromPath(path, { delimiter: '|', columns: true }).transform(function (data){ // do things with your data if (data.NAME[0] === '#') { metadata.push(data.NAME) } else { return data } }).on('data', function (data, index) { console.log('#%d %s', index, JSON.stringify(data, null, ' ')) }).on('end',function (count) { console.log('Metadata: %s', JSON.stringify(metadata, null, ' ')) console.log('Number of lines: %d', count) }).on('error', function (error) { console.error('csv parsing error: %s', error.message) }) }) 

如果您使用的是MacOS或Linux,则可以使用unzip命令从stdin解压缩。

在这个例子中,我正在从文件系统中读取zip文件到一个Buffer对象中,但是它也与下载的文件一起工作:

 // Get a Buffer with the zip content var fs = require("fs") , zip = fs.readFileSync(__dirname + "/test.zip"); // Now the actual unzipping: var spawn = require('child_process').spawn , fileToExtract = "test.js" // -p tells unzip to extract to stdout , unzip = spawn("unzip", ["-p", "/dev/stdin", fileToExtract ]) ; // Write the Buffer to stdin unzip.stdin.write(zip); // Handle errors unzip.stderr.on('data', function (data) { console.log("There has been an error: ", data.toString("utf-8")); }); // Handle the unzipped stdout unzip.stdout.on('data', function (data) { console.log("Unzipped file: ", data.toString("utf-8")); }); unzip.stdin.end(); 

这实际上只是节点版本:

 cat test.zip | unzip -p /dev/stdin test.js 

编辑 :值得注意的是,如果input压缩文件太大,无法从标准input读取一个块,这将不起作用。 如果您需要读取更大的文件,并且您的zip文件只包含一个文件,则可以使用funzip而不是unzip

 var unzip = spawn("funzip"); 

如果您的zip文件包含多个文件(并且您想要的文件不是第一个文件),我不敢说你运气不好。 解压缩需要在.zip文件中查找,因为zip文件只是一个容器,解压缩可能只是解压缩最后一个文件。 在这种情况下,您必须暂时保存文件( 节点温度派上用场)。

前两天,模块node-zip已经发布了,它是Zip: JSZip的唯一版本的包装器。

 var NodeZip = require('node-zip') , zip = new NodeZip(zipBuffer.toString("base64"), { base64: true }) , unzipped = zip.files["your-text-file.txt"].data; 

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

//将a.zip解压到当前字典

('./path/a.zip')。pipe(unzip.Extract({path:'./path/'}));

我用解压缩模块,它的工作。