如何创build一个含有大量文件的Gulp ZIP文件?
我有一个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文件被写入,而无需打开所有的文件?
谢谢。
有关信息:节点5.5.0 / npm 3.8.5 / archiver 1.0.0 / windows
Gulp已经处理了很多你想要做的事情:
-
gulp.src()
读取文件内容,并为每个文件调用fs.stat()
。 然后将它们作为file.contents
和file.stat
存储在它发出的vinyl-file
对象上。 - 这是通过使用
graceful-fs
包来实现的,该包在EMFILE错误的情况下自动退避,并在另一个文件closures时重试。 这可以防止您遇到的“太多打开文件”的问题。
不幸的是,你并没有利用这些优势,因为:
- 你正在调用
fs.statSync()
和fs.createReadStream()
。 真的没有这个必要,因为吞咽已经为你做了。 您有效地读取每个文件两次(并在该过程中创build两倍的文件描述符)。 - 通过直接使用
fs
模块来避免EMFILE内置的保护,避免了“太多打开的文件”问题。
我已经重写了您的代码,以利用吞咽function。 我也试着让它更具吸引力,例如通过使用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(); })); });