如何在node-js中读取和处理大型zip文件

时间:2014-09-05 11:02:34

标签: javascript node.js

我需要读取node-js中的一个大型zip文件并处理每个文件(大约100MB的zip文件包含大约40.000个XML文件,每个文件500kb未压缩)。我正在寻找一个具有可接受速度的“流媒体”解决方案,并且不需要将整个数据集保存在内存中(JSZip,node-zip对我有效,但它将所有内容保存在RAM中并且性能不够好)。对c#的快速尝试表明,在2岁的笔记本电脑上使用DotNetZip可以在大约9秒内完成加载,解包和解析XML。我不认为nodejs会那么快,但是不到一分钟就可以了。将文件解压缩到本地磁盘然后处理它不是一种选择。

我目前正在尝试使用unzip模块(https://www.npmjs.org/package/unzip),但无法使其正常工作,所以我不知道速度是否合适,但至少它看起来像我可以流式传输每个文件并在回调中处理它。 (问题是我只接收前两个条目,然后它停止调用.on('entry', callback)回调。我没有收到任何错误,它只是在2个文件后静默停止。我也很高兴知道我是怎么回事可以在一个块中获取完整的XML,而不是在缓冲区之后获取缓冲区。)

    function openArchive(){
      fs.createReadStream('../../testdata/small2.zip')
        .pipe(unzip.Parse())
        .on('entry', function (entry) {
            var fileName = entry.path;
            var type = entry.type; // 'Directory' or 'File'
            var size = entry.size;
            console.log(fileName);
            entry.on('data', function(data){
              console.log("received data");
            });
        });
    }

有很多用于处理zip文件的node-js模块,所以这个问题实际上是要找出最适合这种情况的库。

2 个答案:

答案 0 :(得分:0)

你必须调用.autodrain()或管道数据到另一个流

entry.on('data', function(data) {
    entry.autodrain();
    // or entry.pipe(require('fs').createWriteStream(entry.path))
});

答案 1 :(得分:0)

我有相同的任务要做:处理100+ MB的zip存档,每个存档中包含100000+的XML文件。在这种情况下,解压缩磁盘上的文件只会浪费HD空间。我尝试使用adm-zip,但是它将在RAM中加载并扩展整个存档,而我的脚本将在大约1400 MB RAM使用时中断。

使用问题中的代码以及Dilan的回答的精妙提示,有时我只会得到部分XML内容,这当然会破坏我的XML解析器。

经过一些试验,我最终得到了该代码:

// process one .zip archive
function process_archive(filename) {
    fs.createReadStream(filename)
        .pipe(unzip.Parse())
        .on('entry', function (entry) {
            // entry.path is file name
            // entry.type is 'Directory' or 'File'
            // entry.size is size of file
            const chunks = [];
            entry.on('data',  (data) => chunks.push(data));
            entry.on('error', (err)  => console.log(err));
            entry.on('end', () => {
                let content = Buffer.concat(chunks).toString('utf8');
                process_my_file(entry.path, content);
                entry.autodrain();
            });
        });

    return;
}

如果这可以帮助任何人,那么它运行起来非常快并且对我来说效果很好,仅使用最大25 MB的RAM。