前阵子,项目上需要实现对zip包进行解压,生成文档树,然后进行修改文件内容,重新压缩生成zip压缩包。
步骤
- 使用zip.js进行读取zip文件
- 使用JSzip进行压缩
工具包使用说明
1. zip.js使用web worker实现
阮一峰-Web Worker 使用教程
Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。
这样做的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。
2. zip.js 提供了文件的读写操作api
操作文档
读取zip
// 动态加载zipjs文件资源
async function loadzipjs() {
setLoading(true);
if (window.zip) return;
await loadResources(['zipjs/zip.js', 'zipjs/zip-ext.js', 'zipjs/zip-fs.js'], false);
window.zip.workerScriptsPath = `${window.location.origin}/zipjs/`;
}
// 读取zip目录
function readZip(url) {
if (!url) return;
setLoading(true);
window.zip.createReader(
new window.zip.HttpReader(url),
function (reader) {
reader.getEntries(async function (entries) {
const data = await getPathTree(entries, reader);
updateTree(data);
setLoading(false);
});
},
function (error) {
Notification.error({ message: '读取zip压缩包失败!' });
console.log('readZip 读取zip失败!', error);
setLoading(false);
// onerror callback
},
);
}
解析文件树
// 根据文件路径获取文件目录
async function getPathTree(entries, reader) {
const tree = [];
const _entries = await Promise.all(
entries.map(async (entry) => {
return new Promise((resolve) => {
entry.getData(new window.zip.TextWriter(), function (text) {
resolve({
...entry,
content: text,
});
});
});
}),
);
reader.close();
_entries.forEach((entry) => {
const splitPath = entry.filename.replace(/^\/|\/$/g, '').split('/');
let ptr = tree;
for (let i = 0; i < splitPath.length; i++) {
const node = {
id: uuid(),
name: splitPath[i],
filename: entry.filename,
directory: true,
};
if (i == splitPath.length - 1) {
node.id = uuid();
node.directory = false;
node.entry = entry;
node.content = entry.content;
}
const itemIndex = ptr.findIndex((item) => {
return item.name === splitPath[i];
});
// 找不到则添加
if (itemIndex < 0) {
ptr.push({
...node,
children: [],
});
}
let index = itemIndex > -1 ? itemIndex : ptr.length - 1;
ptr = ptr[index].children;
}
});
return mapTree(tree, ({ node, children }) => ({
...node,
children: isValidArray(children) ? children : null,
}));
}
生成zip
// 生成zip
function exportZip(treeData, zipName = 'result.zip') {
var zip = new JSZip();
forEachTree(treeData, ({ node }) => {
if (!isNullOrUndefined(node.content)) {
zip.file(node.filename, node.content);
}
});
zip.generateAsync({ type: 'blob' }).then(function (blob) {
download(blob, zipName);
});
}