Node.js 实现 gzip 和 br 压缩类
github https://github.com/xieerduos/nodejs-br-gzip-class
下面是一个扩展的 Node.js 类,该类支持文件和文件夹的压缩与解压。
如果未指定输出路径,则会在原文件或文件夹的同级目录下创建.br
或.gz
文件。
javascript
const fs = require("fs");
const path = require("path");
const zlib = require("zlib");
const { promisify } = require("util");
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
class FileCompressor {
constructor() {
this.brotliOptions = {
params: {
[zlib.constants.BROTLI_PARAM_QUALITY]:
zlib.constants.BROTLI_MAX_QUALITY,
},
};
this.gzipOptions = {
level: zlib.constants.Z_MAX_LEVEL,
};
}
async compressFile(inputPath, outputPath, compressFunction) {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outputPath);
const compressionStream = compressFunction();
fs.createReadStream(inputPath)
.pipe(compressionStream)
.pipe(output)
.on("finish", () => resolve(`Compression completed: ${outputPath}`))
.on("error", reject);
});
}
async decompressFile(inputPath, outputPath, decompressFunction) {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outputPath);
const decompressionStream = decompressFunction();
fs.createReadStream(inputPath)
.pipe(decompressionStream)
.pipe(output)
.on("finish", () => resolve(`Decompression completed: ${outputPath}`))
.on("error", reject);
});
}
async compressDirectory(inputPath, outputPath, compressFunction, extension) {
const files = await readdir(inputPath);
for (let file of files) {
const fullInputPath = path.join(inputPath, file);
const fullOutputPath = path.join(outputPath, `${file}${extension}`);
const fileInfo = await stat(fullInputPath);
if (fileInfo.isDirectory()) {
await this.compressDirectory(
fullInputPath,
fullOutputPath,
compressFunction,
extension
);
} else {
if (!fs.existsSync(fullOutputPath)) {
await this.compressFile(
fullInputPath,
fullOutputPath,
compressFunction
);
}
}
}
}
async compress(inputPath, outputPath, useBrotli = true) {
const fileInfo = await stat(inputPath);
const extension = useBrotli ? ".br" : ".gz";
const compressFunction = useBrotli
? () => zlib.createBrotliCompress(this.brotliOptions)
: () => zlib.createGzip(this.gzipOptions);
if (!outputPath) {
outputPath = inputPath + extension;
}
if (fileInfo.isDirectory()) {
await this.compressDirectory(
inputPath,
outputPath,
compressFunction,
extension
);
} else {
if (fs.existsSync(outputPath)) {
fs.unlinkSync(outputPath);
}
await this.compressFile(inputPath, outputPath, compressFunction);
}
}
async decompress(inputPath, outputPath, useBrotli = true) {
const fileInfo = await stat(inputPath);
const decompressFunction = useBrotli
? () => zlib.createBrotliDecompress()
: () => zlib.createGunzip();
if (!outputPath) {
// Remove the extension (.br or .gz) for the decompressed file's path
outputPath = inputPath.replace(
new RegExp(`${useBrotli ? ".br$" : ".gz$"}`),
""
);
}
if (fileInfo.isDirectory()) {
throw new Error(
"Decompressing directories is not supported directly. Please decompress individual files."
);
} else {
await this.decompressFile(inputPath, outputPath, decompressFunction);
}
}
}
module.exports = FileCompressor;
使用说明:
- 创建
FileCompressor
类的实例。 - 使用实例的
compress
方法进行压缩,它接受三个参数:inputPath
(输入文件或文件夹的路径),outputPath
(可选,输出文件或文件夹的路径),useBrotli
(布尔值,表示是否使用 Brotli 压缩,默认为 true)。
示例代码:
javascript
// @ts-ignore
const FileCompressor = require("./FileCompressor.js");
const compressor = new FileCompressor();
const fs = require("fs");
const path = require("path");
main();
async function main() {
const filePath = path.join(__dirname, "test.jpg");
if (!fs.existsSync(filePath)) {
console.log(`filePath: ${filePath} 路径不存在`);
return;
}
if (fs.existsSync(filePath + ".br")) {
fs.unlinkSync(filePath + ".br");
}
if (fs.existsSync("./test2.jpg")) {
fs.unlinkSync("./test2.jpg");
}
await new Promise((resolve) => setTimeout(resolve, 1000));
// br 压缩
await compressor.compress(filePath).then(console.log).catch(console.error);
// gzip 压缩
await compressor
.compress(filePath, undefined, false)
.then(console.log)
.catch(console.error);
// 解压
await compressor
.decompress("test.jpg.br", "test2.jpg")
.then(console.log)
.catch(console.error);
}
更多示例
js
const compressor = new FileCompressor();
// 压缩单个文件,自动在同一位置创建 .br 文件
compressor
.compress("path/to/input.txt")
.then(console.log) // 输出成功消息
.catch(console.error); // 捕获并显示错误
// 压缩单个文件,使用Gzip而非Brotli
compressor
.compress("path/to/input.txt", undefined, false)
.then(console.log) // 输出成功消息
.catch(console.error); // 捕获并显示错误
// 压缩文件夹,自动在同一位置创建带 .br 扩展的文件夹
compressor
.compress("path/to/inputFolder")
.then(console.log) // 输出成功消息
.catch(console.error); // 捕获并显示错误
// 压缩文件夹,使用Gzip压缩
compressor
.compress("path/to/inputFolder", undefined, false)
.then(console.log) // 输出成功消息
.catch(console.error); // 捕获并显示错误