需要使用Node.js压缩整个目录


107

我需要使用Node.js压缩整个目录。我当前使用的是node-zip,每次运行该进程时,它都会生成一个无效的ZIP文件(如您从此Github问题中所见)。

还有另一个更好的Node.js选项,它允许我压缩目录吗?

编辑:我最终使用存档器

writeZip = function(dir,name) {
var zip = new JSZip(),
    code = zip.folder(dir),
    output = zip.generate(),
    filename = ['jsd-',name,'.zip'].join('');

fs.writeFileSync(baseDir + filename, output);
console.log('creating ' + filename);
};

参数样本值:

dir = /tmp/jsd-<randomstring>/
name = <randomstring>

更新:对于那些询问我使用的实现的人,这是我的下载器的链接


3
Twitter上有人建议使用child_process API,只需调用系统ZIP:nodejs.org/api/child_process.html
commadelimited 2013年

1
我已经尝试过child_process方法。有两个警告。 1) unix zip命令在压缩文件中包含当前工作目录的所有父文件夹层次结构。这对您可能没问题,对我而言不是。另外,以某种方式更改child_process中的当前工作目录不会影响结果。 2)要解决此问题,您必须使用pushd跳转到将zip和压缩的文件夹zip -r,但是由于pushd 内置于bash而非/ bin / sh中,因此您还需要使用/ bin / bash。在我的特定情况下,这是不可能的。只是抬头。
johnozbay

2
@johnozbay节点的child_process.execapi使您可以从要运行命令的位置指定cwd。更改CWD确实可以解决父文件夹层次结构的问题。它还解决了不需要的问题pushd。我完全推荐child_process。
Govind Rai

1
使用child_process api的stackoverflow.com/a/49970368/2757916本机nodejs解决方案。2行代码。没有第三方库。
Govind Rai '18

@GovindRai非常感谢!
johnozbay

Answers:


124

我最终使用了存档器库。效果很好。

var file_system = require('fs');
var archiver = require('archiver');

var output = file_system.createWriteStream('target.zip');
var archive = archiver('zip');

output.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.on('error', function(err){
    throw err;
});

archive.pipe(output);

// append files from a sub-directory and naming it `new-subdir` within the archive (see docs for more options):
archive.directory(source_dir, false);
archive.finalize();

1
似乎没有如何执行此操作的示例,您是否愿意分享所做的事情?
Sinetheta

1
不幸的是,存档器目前不支持文件名中的Unicode字符。报告给github.com/ctalkington/node-archiver/issues/90
Eye

2
如何递归包括所有文件和目录(还包括隐藏的文件/目录)?
尼卡比曹

12
存档器现在使这变得更加简单。现在,您可以使用directory()而不是使用bulk()方法:npmjs.com/package/archiver#directory-dirpath-destpath-data
Josh Feldman

14
.bulk已弃用
弯曲的曲线图,2017年

46

我不假装展示一些新东西,只是想为那些喜欢在其代码中使用Promise函数的人(如我)总结以上解决方案。

const archiver = require('archiver');

/**
 * @param {String} source
 * @param {String} out
 * @returns {Promise}
 */
function zipDirectory(source, out) {
  const archive = archiver('zip', { zlib: { level: 9 }});
  const stream = fs.createWriteStream(out);

  return new Promise((resolve, reject) => {
    archive
      .directory(source, false)
      .on('error', err => reject(err))
      .pipe(stream)
    ;

    stream.on('close', () => resolve());
    archive.finalize();
  });
}

希望它能帮助某人;)


这里到底是什么?我认为源是目录的路径
梦想

@Tarun完整zip的路径,例如:/User/mypc/mydir/test.zip
D.Dimitrioglo,

无法解压缩zip文件。不允许操作
Jake

@ ekaj_03,请确保您具有指定目录的足够权限
D.Dimitrioglo,

1
@ D.Dimitrioglo都很好。这是源目录问题。谢谢:)
杰克

17

使用Node的本机child_processapi完成此操作。

无需第三方库。两行代码。

const child_process = require("child_process");
child_process.execSync(`zip -r DESIRED_NAME_OF_ZIP_FILE_HERE *`, {
  cwd: PATH_TO_FOLDER_YOU_WANT_ZIPPED_HERE
});

我正在使用同步API。child_process.exec(path, options, callback)如果需要异步,可以使用。除了指定CWD进一步细化您的请求外,还有更多选择。请参阅exec / execSync文档。


请注意: 此示例假定您在系统上安装了zip实用程序(至少OSX随附)。某些操作系统可能未安装实用程序(即,AWS Lambda运行时未安装)。在这种情况下,您可以在此处轻松获取zip实用程序二进制文件并将其与应用程序源代码打包在一起(对于AWS Lambda,您也可以将其打包在Lambda层中),或者您必须使用第三方模块(其中NPM有很多)。我更喜欢前一种方法,因为ZIP实用程序经过数十年的尝试和测试。


9
不幸的是,仅适用于具有的系统zip
janpio

3
出于避免在我的项目中使用数十个外部库的目的而选择了此解决方案
EAzevedo,

这是有道理的,但是如果我没有记错的话,这将再次困扰Windows用户。请想想Windows用户!
Mathijs Segers,

@MathijsSegers哈哈!这就是为什么我包括指向二进制文件的链接,以便Windows用户也可以获取它的原因!:)
Govind Rai

有没有办法使它适用于项目中的目录而不是计算机目录?
马特·克鲁克

13

Archive.bulk现在已弃用,用于此目的的新方法是glob

var fileName =   'zipOutput.zip'
var fileOutput = fs.createWriteStream(fileName);

fileOutput.on('close', function () {
    console.log(archive.pointer() + ' total bytes');
    console.log('archiver has been finalized and the output file descriptor has closed.');
});

archive.pipe(fileOutput);
archive.glob("../dist/**/*"); //some glob pattern here
archive.glob("../dist/.htaccess"); //another glob pattern
// add as many as you like
archive.on('error', function(err){
    throw err;
});
archive.finalize();

2
对此感到疑惑的是,他们说不建议使用批量功能,但没有建议改用哪个功能。
jarodsmk

1
您如何指定“源”目录?
做梦


2020年:archive.directory()更简单了!
OhadR


9

这是另一个将文件夹压缩为一行的库: zip-local

var zipper = require('zip-local');

zipper.sync.zip("./hello/world/").compress().save("pack.zip");

4
就像一种魅力一样,不同于互联网上或上面提到的其他数十种魅力,它们总是为我生成“零字节”文件
Sergey Pleshakov

4

将结果通过管道传递到响应对象(需要下载zip而不是在本地存储的情况)

 archive.pipe(res);

Sam关于访问目录内容的提示对我有用。

src: ["**/*"]

3

Adm-zip仅压缩现有归档文件https://github.com/cthackers/adm-zip/issues/64时就会出现问题,并且压缩二进制文件时也会损坏。

我还遇到了node-zip https://github.com/daraosn/node-zip/issues/4的压缩损坏问题

node-archiver是唯一看起来可以很好地压缩的压缩程序,但是它没有任何解压缩功能。


1
您在谈论哪个节点档案?:github.com/archiverjs/node-archiver; github.com/richardbolt/node-archiver
biphobe

@firian他没有说Archiver,而是说Adm-zip。
弗朗西斯·佩兰

5
@FrancisPelland Umm,在最后一句中,他写道“ node-archiver是唯一一个似乎有效的命令 ”-这就是我所指的。
biphobe



1

由于archiver长期以来与新版本的webpack不兼容,我建议使用zip-lib

var zl = require("zip-lib");

zl.archiveFolder("path/to/folder", "path/to/target.zip").then(function () {
    console.log("done");
}, function (err) {
    console.log(err);
});

0

您可以通过一种简单的方式尝试:

安装zip-dir

npm install zip-dir

并使用它

var zipdir = require('zip-dir');

let foldername =  src_path.split('/').pop() 
    zipdir(<<src_path>>, { saveTo: 'demo.zip' }, function (err, buffer) {

    });

是否可以添加参数来制作zip文件夹?像压缩级别和大小,如果要怎么做呢?
Trang D

0

我结束了对Archiver的包装,以模仿JSZip,因为通过我的项目进行重构将花费很多精力。我了解Archiver可能不是最佳选择,但是您可以选择这里。

// USAGE:
const zip=JSZipStream.to(myFileLocation)
    .onDone(()=>{})
    .onError(()=>{});

zip.file('something.txt','My content');
zip.folder('myfolder').file('something-inFolder.txt','My content');
zip.finalize();

// NodeJS file content:
    var fs = require('fs');
    var path = require('path');
    var archiver = require('archiver');

  function zipper(archive, settings) {
    return {
        output: null,
        streamToFile(dir) {
            const output = fs.createWriteStream(dir);
            this.output = output;
            archive.pipe(output);

            return this;
        },
        file(location, content) {
            if (settings.location) {
                location = path.join(settings.location, location);
            }
            archive.append(content, { name: location });
            return this;
        },
        folder(location) {
            if (settings.location) {
                location = path.join(settings.location, location);
            }
            return zipper(archive, { location: location });
        },
        finalize() {
            archive.finalize();
            return this;
        },
        onDone(method) {
            this.output.on('close', method);
            return this;
        },
        onError(method) {
            this.output.on('error', method);
            return this;
        }
    };
}

exports.JSzipStream = {
    to(destination) {
        console.log('stream to',destination)
        const archive = archiver('zip', {
            zlib: { level: 9 } // Sets the compression level.
        });
        return zipper(archive, {}).streamToFile(destination);
    }
};
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.