如何创建包含大量文件的 Gulp 的 ZIP 文件?

How to create a ZIP file with Gulp that contains a lot of files?

我有一个 Gulp 任务,我在 ZIP 文件中添加大量文件(在一种情况下超过 2700 个,但在其他情况下可能有数千个)。代码如下:

const fs = require('fs');
const archiver = require('archiver')('zip');

let zip = fs.createWriteStream('my-archive.zip');
return gulp.src('app/**/*')
  .pipe(through.obj((file, encoding, cb) => {
    let pathInZip = '...';
    if (!isADirectory(file.path)) { // Do not zip the directory itself
      archiver.append(fs.createReadStream(file.path), {
        name: pathInZip,
        mode: fs.statSync(file.path)
      });
    }
    cb(null, file);
  }, cb => {
    // Now create the ZIP file!
    archiver.pipe(zip);
    archiver.finalize();
    cb();
  }));

此代码适用于小型项目,但当它处理超过 2000 个文件时,出现以下错误:

events.js:154
throw er; // Unhandled 'error' event
^

Error: EMFILE: too many open files, open 'd:\dev\app\some\file'
at Error (native)

所以我明白在将它们写入 ZIP 之前同时打开 2000 多个文件并不是一个好主意。

如何在不需要打开所有文件的情况下要求写入 ZIP 文件?

谢谢。

有关信息:node 5.5.0 / npm 3.8.5 / archiver 1.0.0 / windows

Gulp 已经处理了很多你想做的事情:

  • gulp.src() 读取文件内容并对每个文件进行 fs.stat() 调用。然后它将两者存储为它发出的 file.contents and file.stat on the vinyl-file 个对象。
  • 它通过使用 graceful-fs 程序包来实现,该程序包会在出现 EMFILE 错误时自动退出,并在另一个文件关闭时重试。这可以防止您遇到的 "too many open files" 问题。

很遗憾,您没有利用其中任何一个,因为:

  • 您正在显式调用 fs.statSync()fs.createReadStream()。确实没有必要,因为 gulp 已经为您完成了。您有效地读取了每个文件两次(并在此过程中创建了两倍数量的文件描述符)。
  • 您通过直接使用 fs 模块来规避 gulp 针对 EMFILE 的内置保护,该模块没有针对 "too many open files" 问题的任何防护措施。

我重写了您的代码以利用 gulp 的功能。我也试着让它更 gulp-地道一点,例如通过使用 gulp-filter 删除目录:

const gulp = require('gulp');
const fs = require('graceful-fs');
const archiver = require('archiver')('zip');
const through = require('through2');
const filter = require('gulp-filter');

gulp.task('default', () => {
  var zip = fs.createWriteStream('my-archive.zip');
  archiver.pipe(zip);
  return gulp.src('app/**/*')
    .pipe(filter((file) => !file.stat.isDirectory()))
    .pipe(through.obj((file, encoding, cb) => {
      var pathInZip = '...';
      archiver.append(file.contents, {
        name: pathInZip,
        mode: file.stat
      });
      cb(null, file);
    }, cb => {
      zip.on('finish', cb);
      archiver.finalize();
    }));
});