如何创建包含大量文件的 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();
}));
});
我有一个 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
andfile.stat
on thevinyl-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();
}));
});