我需要使用 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>
更新:对于那些询问我使用的实现的人,这是我的下载器的链接:
我最终使用了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();
我不打算展示新的东西,只是想为那些像我一样喜欢 Promise 的人总结上面的解决方案😉。
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();
});
}
希望它能帮助某人🤞
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
实用程序。为了完整起见,某些操作系统默认情况下可能没有安装实用程序。在这种情况下,您至少有三个选择:
使用您平台本机的归档/压缩实用程序
将上述 Node.js 代码中的 shell 命令替换为您系统中的代码。例如,Linux 发行版通常附带
tar
/gzip
实用程序:
tar -cfz <DESIRED_NAME_OF_ZIP_FILE_HERE> <PATH_TO_FOLDER_YOU_WANT_ZIPPED_HERE>
.
这是一个不错的选择,因为您不需要在操作系统上安装任何新内容或管理另一个依赖项(这就是这个答案的全部要点)。
获取适用于您的操作系统/发行版的
zip
二进制文件。
例如在 Ubuntu 上:
apt install zip
。
ZIP 实用程序已经过数十年的尝试和测试,它相当普遍,并且是一个安全的选择。快速进行谷歌搜索或访问创建者 Info-ZIP 的网站以获取可下载的二进制文件。
使用第三方库/模块(NPM 上有很多)。
我不喜欢这个选项。但是,如果您并不真正关心了解本机方法并且引入新的依赖项不是问题,那么这也是一个有效的选择。
这是另一个库,它将文件夹压缩为一行: zip-本地
var zipper = require('zip-local');
zipper.sync.zip("./hello/world/").compress().save("pack.zip");
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();
要包含所有文件和目录:
archive.bulk([
{
expand: true,
cwd: "temp/freewheel-bvi-120",
src: ["**/*"],
dot: true
}
]);
它在下面使用node-glob(https://github.com/isaacs/node-glob),因此任何与其兼容的匹配表达式都可以工作。
将结果通过管道传输到响应对象(需要下载 zip 而不是本地存储的场景)
archive.pipe(res);
Sam 关于访问目录内容的提示对我有用。
src: ["**/*"]
由于
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);
});
Adm-zip 在压缩现有存档时存在问题 https://github.com/cthackers/adm-zip/issues/64 以及压缩二进制文件时出现损坏。
我还遇到了 node-zip 的压缩损坏问题 https://github.com/daraosn/node-zip/issues/4
node-archiver 是唯一一个似乎可以很好地压缩但它没有任何解压缩功能的工具。
今天,我正在使用 AdmZip 并且效果很好:
const 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}`);
}
}
我找到了这个小库,它封装了您需要的内容。
npm install zip-a-folder
const zipAFolder = require('zip-a-folder');
await zipAFolder.zip('/path/to/the/folder', '/path/to/archive.zip');
import
...
from
答案基于 https://stackoverflow.com/a/51518100
到 zip 单个目录
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();
});
}
你可以尝试一下简单的方法:
安装
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 来模拟 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);
}
};
const express = require("express");
const { createGzip } = require("node:zlib");
const { pipeline } = require("node:stream");
const { createReadStream, createWriteStream } = require("node:fs");
const app = express();
app.use(express.json());
app.get("/", async (req, res) => {
const gzip = createGzip();
const source = createReadStream("hotellists.json");
const destination = createWriteStream("hotellists.json.gz");
pipeline(source, gzip, destination, (err) => {
if (err) {
console.error("An error occurred:", err);
process.exitCode = 1;
}
});
});
app.listen(2020, () => console.log("server in on"));