import JSZip from 'jszip';
import { extname, join, relative, sep, dirname } from 'path';
import { pathExists, Stats, stat, readdir, readFile, writeFile, ensureDir } from 'fs-extra';
/**
* 递归文件执行回调函数
* @param dirPath
* @param handle
* @returns
*/
const recursive = async (
dirPath: string,
handle: (file: string, ext: string, stat: Stats) => Promise<void>,
): Promise<void> => {
if (!(await pathExists(dirPath))) return; // 如果路径不存在,直接返回
const fileStats: Stats = await stat(dirPath);
if (fileStats.isSymbolicLink()) return; // 如果是软链接,那么就直接跳过
if (fileStats.isDirectory()) {
const fileList = await readdir(dirPath, { withFileTypes: true });
for (let i = 0, len = fileList.length; i < len; i++) {
const temp = fileList[i];
await recursive(join(dirPath, temp.name), handle);
}
} else if (fileStats.isFile()) {
// 如果不存在需要过滤的,或者匹配上过虑的,那么执行回调
await handle(dirPath, extname(dirPath), fileStats);
}
};
/**
* 实现文件压缩
* @param {string} targetPath 目标路径
* @param {string} destPath 压缩后的路径
* @param {number} level 压缩等级
*/
export const zip = async (
targetPath: string,
destPath: string,
level: number = 1,
): Promise<void> => {
if (!(await pathExists(targetPath))) throw new Error('Zip requires a valid address');
const zipHandle = new JSZip();
// const folderName = basename(targetPath);
await recursive(targetPath, async (file: string) => {
const fileContent = await readFile(file);
zipHandle
// .folder(folderName) //外面不需要再包一层文件夹
?.file(relative(targetPath, file).split(sep).join('/'), fileContent);
});
const buffer = await zipHandle.generateAsync({
type: 'nodebuffer',
compression: 'DEFLATE',
compressionOptions: { level },
});
await writeFile(destPath, buffer);
};
/**
* 实现zip文件解压
* @param {string} targetPath 源文件地址
* @param {string} destPath 目标地址
*/
export const unzip = async (targetPath: string, destPath: string): Promise<void> => {
if (!(await pathExists(targetPath))) throw new Error('zip path is invalid');
const zipHandle = new JSZip();
const buffer = await readFile(targetPath);
const handle: JSZip = await zipHandle.loadAsync(buffer, { createFolders: false });
const { files } = handle;
const keys = Object.keys(files);
for (let i = 0, len = keys.length; i < len; i++) {
const temp = join(destPath, keys[i]);
await ensureDir(dirname(temp));
if (!handle.files[keys[i]].dir) {
const content = await handle.files[keys[i]].async('nodebuffer');
await writeFile(temp, content);
}
}
};