【问题标题】:how to read and process large zip files in node-js如何在 node-js 中读取和处理大型 zip 文件
【发布时间】:2014-09-05 11:02:33
【问题描述】:

我需要在 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)但无法使其工作,所以我不知道速度是否还可以,但至少看起来我可以流式传输每个文件并在回调中处理它。 (问题是我只收到前 2 个条目,然后它停止调用 .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");
            });
        });
    }

有很多 node-js 模块用于处理 zip 文件,所以这个问题真的是要弄清楚哪个库最适合这种情况。

【问题讨论】:

  • 当你说你“不能让它工作” - 什么问题?什么错误?其他人很难对一般性陈述进行故障排除。
  • 我提到了什么不起作用。上面的代码只从一个 zip 文件中读取两个文件。

标签: javascript node.js


【解决方案1】:

您必须调用 .autodrain() 或将数据传输到另一个流

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

【讨论】:

    【解决方案2】:

    我有同样的任务要做:处理 100+ MB 的 zip 档案,每个档案中包含 100 000+ 个 XML 文件。在这种情况下,解压缩磁盘上的文件只是浪费硬盘空间。我尝试了 adm-zip,但它会在 RAM 中加载和扩展整个存档,并且我的脚本会在大约 1 400 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-10-10
      • 1970-01-01
      • 1970-01-01
      • 2021-03-19
      • 2021-03-07
      • 2016-03-28
      • 2022-01-26
      • 1970-01-01
      相关资源
      最近更新 更多