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

我需要使用 Node.js 压缩整个目录。我目前正在使用 node-ZIP,并且每次进程运行时都会生成一个无效的 ZIP 文件(从 这个 Github 问题可以看到)。

还有其他更好的 Node.js 选项允许我压缩目录吗?

编辑: 我最终使用了 Archiver

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>

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

186663 次浏览

Adm-zip 在压缩现有存档 https://github.com/cthackers/adm-zip/issues/64时存在问题,压缩二进制文件时也会出现问题。

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

Node-archive 似乎是唯一一个能够很好地进行压缩的程序,但是它没有任何解压缩功能。

我最终使用 Archiver lib。工作得很好。

例子

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, putting its contents at the root of archive
archive.directory(source_dir, false);


// append files from a sub-directory and naming it `new-subdir` within the archive
archive.directory('subdir/', 'new-subdir');


archive.finalize();

包含所有文件和目录:

archive.bulk([
{
expand: true,
cwd: "temp/freewheel-bvi-120",
src: ["**/*"],
dot: true
}
]);

它在下面使用 node-globb (https://github.com/isaacs/node-glob) ,因此任何与之兼容的匹配表达式都可以工作。

将结果传送到响应对象(需要下载 zip 而不是本地存储的场景)

 archive.pipe(res);

山姆提供的访问目录内容的提示对我很有用。

src: ["**/*"]

Archive.bulk现在已经被废弃,用于这个的新方法是 一团:

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();

使用 Node 的原生 child_process api 来完成这项工作。

不需要第三方解释,两行代码。

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之外,还可以指定更多的 选择来进一步微调您的请求。


如果您没有 ZIP 实用程序:

这个问题是 特别是为了存档/压缩的目的而询问关于 zip实用程序的问题。因此,本示例假设您在系统上安装了 zip实用程序。出于完整性的考虑,有些操作系统默认情况下可能没有安装实用程序。在这种情况下,你至少有三种选择:

  1. 使用平台本地的归档/压缩实用程序

    用您系统中的代码替换上面 Node.js 代码中的 shell 命令。例如,Linux 发行版通常附带 tar/gzip实用程序:

    tar -cfz <DESIRED_NAME_OF_ZIP_FILE_HERE> <PATH_TO_FOLDER_YOU_WANT_ZIPPED_HERE>.

    这是一个不错的选择,因为您不需要在操作系统上安装任何新的东西,也不需要管理另一个依赖项(这是这个答案的全部要点)。

  2. 获取操作系统/发行版的 zip二进制文件。

    比如 Ubuntu: apt install zip

    ZIP 实用程序经过了几十年的试验和测试,它相当普遍,是一个安全的选择。做一个快速谷歌搜索或去创建者,信息邮政编码的,可下载二进制文件的网站。

  3. 使用第三方库/模块(NPM 上有很多这样的库/模块)。

    我不喜欢这个选择。但是,如果您并不真正关心理解本机方法,并且引入一个新的依赖项是没有问题的,那么这也是一个有效的选择。

我不打算展示什么新的东西,只是想总结上面的解决方案给那些和我一样喜欢承诺的人。

const archiver = require('archiver');


/**
* @param {String} sourceDir: /some/folder/to/compress
* @param {String} outPath: /path/to/created.zip
* @returns {Promise}
*/
function zipDirectory(sourceDir, outPath) {
const archive = archiver('zip', { zlib: { level: 9 }});
const stream = fs.createWriteStream(outPath);


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


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

希望能帮到别人

这是另一个将文件夹压缩成一行的库: 本地邮编

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


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

我已经找到了这个小库,它封装了您所需要的内容。

npm install zip-a-folder


const zip-a-folder = require('zip-a-folder');
await zip-a-folder.zip('/path/to/the/folder', '/path/to/archive.zip');

Https://www.npmjs.com/package/zip-a-folder

你可以试试一个简单的方法:

安装 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) {


});

由于 archiver与新版本的 webpack 长期不兼容,我建议使用 自由自在

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


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

最后,我用包装归档器来模拟 JSZip,因为通过我的项目进行重构需要花费太多的精力。我知道阿奇弗可能不是最好的选择但给你。

// 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);
}
};

基于 https://stackoverflow.com/a/51518100from应答

压缩单目录

import archiver from 'archiver';
import fs from 'fs';


export default zipDirectory;


/**
* From: https://stackoverflow.com/a/51518100
* @param {String} sourceDir: /some/folder/to/compress
* @param {String} outPath: /path/to/created.zip
* @returns {Promise}
*/
function zipDirectory(sourceDir, outPath) {
const archive = archiver('zip', { zlib: { level: 9 }});
const stream = fs.createWriteStream(outPath);


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


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

压缩多个目录:

import archiver from 'archiver';
import fs from 'fs';


export default zipDirectories;


/**
* Adapted from: https://stackoverflow.com/a/51518100
* @param {String} sourceDir: /some/folder/to/compress
* @param {String} outPath: /path/to/created.zip
* @returns {Promise}
*/
function zipDirectories(sourceDirs, outPath) {
const archive = archiver('zip', { zlib: { level: 9 }});
const stream = fs.createWriteStream(outPath);


return new Promise((resolve, reject) => {
var result = archive;
sourceDirs.forEach(sourceDir => {
result = result.directory(sourceDir, false);
});
result
.on('error', err => reject(err))
.pipe(stream)
;


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

和今天一样,我使用 AdmZip,效果很好:

import AdmZip = require('adm-zip');
export async function archiveFile() {
try {
const zip = new AdmZip();
const outputDir = "/output_file_dir.zip";
zip.addLocalFolder("./yourFolder")
zip.writeZip(outputDir);
} catch (e) {
console.log(`Something went wrong ${e}`);
}
}