如果你对开源项目、提升技术、副业、面试、历史等等感兴趣的,可以加我微信 yunmz777,刚好我们有这样的交流群.
在 windows 系统上面,我们压缩文件,常常需要安装一些压缩软件才能实现压缩,可能有些还存在一些问题,例如 winrar 有广告,7z 界面好像比较古老。
那么接下来我们就来学习一下怎么自己实现一个压缩工具,彻底摆脱这些软件。
ZIP 压缩
ZIP 压缩是一种广泛使用的文件压缩格式,它通过减小文件大小来节省存储空间,同时便于文件的传输和分享。ZIP 文件不仅可以包含单个文件,还可以包含多个文件或文件夹,这些文件在压缩过程中会被合并成一个单一的文件,这样就方便了用户管理和传输。
ZIP 压缩算法主要利用了数据中的重复模式来减少文件的大小。当 ZIP 压缩软件发现数据中有重复的内容时,它会用更短的引用来替换这些重复内容,从而达到减少文件大小的目的。这个过程是可逆的,意味着压缩后的文件可以被解压缩回原来的状态,不会有任何数据丢失。
使用 ZIP 压缩的好处包括:
-
节省空间:ZIP 压缩可以显著减少文件的存储空间需求,特别是对于包含大量重复数据的文件。
-
便于传输:减小的文件大小意味着在网络上传输文件所需的时间更短,便于快速分享和下载。
-
整理文件:将多个文件和文件夹打包成单一的 ZIP 文件,可以简化文件管理和分发。
虽然 ZIP 是一种非常有效的压缩格式,但它并不总是能够提供最佳的压缩率。有些特定的压缩算法,比如 7-Zip 的 LZMA 算法,可能在某些情况下提供更好的压缩效率。因此,用户在压缩非常大的文件或需要极致压缩率的场合时,可能会考虑使用这些其他的压缩工具和格式。
实现文件夹压缩
我们最基础的功能就是需要把一个文件夹弄成一个压缩文件,最常见的场景就是微信传文件不能传文件,需要经过压缩:
要想使用,我们需要安装一个 adm-zip
包,它是一个用于 Node.js 的 JavaScript 实现,可以处理 ZIP 文件的压缩和解压。它不依赖于任何原生代码,易于安装和使用。
bash
pnpm add adm-zip
并编写以下代码:
js
const AdmZip = require("adm-zip");
const zip = new AdmZip();
// 添加整个目录到 ZIP 文件
zip.addLocalFolder("./article");
// 定义 ZIP 文件的保存路径
const outputPath = "./output.zip";
// 将 ZIP 文件保存到磁盘
zip.writeZip(outputPath, function (err) {
if (err) {
console.log("发生错误:", err);
} else {
console.log("ZIP 文件成功创建:", outputPath);
}
});
ZIP 文件的创建和内容的添加是在内存中进行的,直到你调用 writeZip 或 toBuffer 等方法将 ZIP 数据实际写入到磁盘或其他存储介质之前,你是看不到任何新文件的。这种方式允许你在保存 ZIP 文件之前灵活地添加或修改内容。
最终输出效果正是我们想要的:
向压缩文件中添加新内容
接下来我们再看看新增内容的,我们首先编写如下代码:
js
const AdmZip = require("adm-zip");
const zip = new AdmZip("./output.zip");
// 向ZIP文件中添加一个新文件,文件名为"newFile.txt",内容为"Hello World"
zip.addFile("moment.txt", Buffer.from("Hello World", "utf-8"));
// 保存更改,覆盖原有的ZIP文件
zip.writeZip("./output.zip");
console.log("新内容已添加到ZIP文件中。");
这段代码首先通过 Adm-Zip 加载一个已有的 ZIP 文件,然后使用 addFile 方法向其中添加一个新的文件。addFile 方法接受两个参数:第一个是要添加的文件名,第二个是文件的内容,以 Buffer 的形式提供。最后,调用 writeZip 方法将更改写回原文件或保存为一个新的 ZIP 文件。
最终输出结果如下图所示:
向压缩文件中删除指定内容
使用 Adm-Zip 删除 ZIP 文件中的内容也非常直接。我们可以使用 deleteFile 方法来删除 ZIP 文件中的指定文件。以下是如何使用 Adm-Zip 删除 ZIP 文件中特定内容的示例:
js
const AdmZip = require("adm-zip");
const zip = new AdmZip("./output.zip");
zip.deleteFile("moment.txt");
zip.writeZip("./output.zip");
console.log("文件已从ZIP中删除。");
这段代码首先加载一个已有的 ZIP 文件,然后使用 deleteFile 方法删除指定的文件。这里,我们通过传递要删除的文件名作为参数来指定哪个文件应该被删除。最后,通过调用 writeZip 方法将更改写回原文件或保存为一个新的 ZIP 文件。
最终代码的输出结果如下图所示:
如何对压缩文件进行解压
使用 Adm-Zip 库在 Node.js 中解压 ZIP 文件同样简单直接。以下是步骤和代码示例,展示如何使用 Adm-Zip 解压 ZIP 文件:
js
const AdmZip = require("adm-zip");
// 指定ZIP文件的路径
const zip = new AdmZip("./output.zip");
// 解压到指定的目录中,第二个参数为是否强制覆盖
zip.extractAllTo("./moment", true);
console.log("ZIP文件已成功解压。");
最终代码输出的结果如下图所示:
加密压缩
创建加密的 ZIP 文件在 Node.js 中稍微复杂一些,因为 Adm-Zip 不直接支持创建加密的 ZIP 文件。对于需要直接创建支持密码保护的 ZIP 文件的场景,可以考虑使用专门的命令行工具(如 7-Zip)通过 Node.js 的 child_process 模块调用。
在 mac 中,首先需要我们安装相对应的工具,如下:
bash
brew install p7zip
安装完成之后,我们要在 node 中编写如下代码:
js
const { exec } = require("child_process");
const password = "moment"; // 替换为你的密码
const inputFile = "./moment"; // 要加密的文件或文件夹路径
const encryptedZip = "./moment.zip"; // 输出的加密ZIP文件路径
const command = `7z a -p${password} -tzip -mem=AES256 ${encryptedZip} ${inputFile}`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`执行的错误: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
if (stderr) {
console.error(`stderr: ${stderr}`);
}
});
在上面的 command 中,定义了一个将要执行的命令字符串。命令使用了 7z(7-Zip 的命令行工具)来创建加密的 ZIP 文件。让我们分解这个命令:
-
7z:调用 7-Zip 命令行工具。
-
a:表示添加文件到压缩文件中。
-
-p${password}
:设置密码用于加密压缩文件。${password}会被之前定义的 password 变量的值替换。 -
-tzip
:指定压缩文件的类型为 ZIP。 -
-mem=AES256:指定使用 AES-256 加密算法进行加密。
-
${encryptedZip} ${inputFile}
:分别是创建的加密 ZIP 文件的路径和要压缩的文件或文件夹的路径。这两个占位符会被相应的变量值替换。
上面代码的执行结果如下图所示:
被我们压缩成功了,且打开的时候需要密码的,输入密码后解压成功:
对加密文件进行解压
要使用 7z 命令实现 ZIP 文件的解压,特别是解压一个使用密码加密的 ZIP 文件,你可以在 Node.js 中使用类似的方法调用 7z 命令。
js
const { exec } = require("child_process");
const password = "moment"; // 用于解压的密码,应与加密时相同
const zipFilePath = "./moment.zip"; // 加密的ZIP文件路径
const outputDir = "./777"; // 解压到的目录路径
const command = `7z x -p${password} -o"${outputDir}" "${zipFilePath}" -y`;
exec(command, (error, stdout, stderr) => {
if (error) {
console.error(`执行的错误: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
if (stderr) {
console.error(`stderr: ${stderr}`);
}
});
在上面的代码中,我们解释一下命令中的各个部分:
-
7z:调用 7-Zip 命令行工具。
-
x:表示解压缩操作。
-
-p <math xmlns="http://www.w3.org/1998/Math/MathML"> p a s s w o r d :提供用于解压的密码, {password}:提供用于解压的密码, </math>password:提供用于解压的密码,{password}会被替换为之前定义的密码变量的值。
-
-o" <math xmlns="http://www.w3.org/1998/Math/MathML"> o u t p u t D i r " :指定解压缩的输出目录, {outputDir}":指定解压缩的输出目录, </math>outputDir":指定解压缩的输出目录,{outputDir}是目标目录路径的变量。注意:路径如果包含空格,应该用引号""包围起来。
-
"${zipFilePath}":指向加密的 ZIP 文件的路径,如果路径包含空格,也应该用引号""包围。
-
-y:自动回答所有提示为'是',例如覆盖现有文件的提示。
使用这个命令,你可以解压一个加密的 ZIP 文件到指定目录,不需要人工干预过程中的任何提示。
最终代码的允许结果如下图所示:
总结
通过上面的案例我们基本已经实现了一个压缩文件中的基本功能了,我们可以将这些思想使用 electron 或者 tauri 编写成一个桌面端,这样我们就不用去安装那些别人的软件了。