微信小程序 - 创建 ZIP 压缩包
- 场景
- 分享代码片段
- 导入 JSZip
- 创建ZIP文件
- 追加写入文件
- 测试方法
- 参考资料
场景
微信小程序只提供了解压ZIP的API,并没有提供创建ZIP的方法。
当我们想把自己处理好的保存,打包ZIP保存下来时就需要自己实现了。
分享代码片段
不想听废话的,直接看代码
https://developers.weixin.qq.com/s/ChblKjmo7ZNd
导入 JSZip
首先需要 jszip
const JSZip = require('../lib/jszip.min');
const fs = wx.getFileSystemManager();
jszip
在微信小程序无法直接跑。要处理一下。把 setImmediate
全部替换为 setTimeout
创建ZIP文件
/*** 文件打包为 zip* @param {*} fileList 文件列表 [{ name: '文件名', path: '文件路径'}]* @param {*} zipPath 保存压缩包的路径* @param {*} progress 处理进度更新时:回调*/
async function zip(fileList, zipPath, progress=res=>console.log){try {// 实例化 jszipvar jszip = new JSZip();// 遍历文件列表,添加到 zip 文件列表中let total = fileList.length;fileList.forEach((file, index) => {jszip.file(file.name, new Uint8Array(fs.readFileSync(file.path)));progress({ percent: Math.round((index+1)/total) * 100, msg: `读取资源 ${index+1}/${total}` });});// 生成压缩包对象(uint8array)let content = await jszip.generateAsync({ type : JSZip.support.uint8array ? "uint8array" : "string" },meta => progress({ percent: Math.floor(meta.percent), msg: `创建 ZIP...` }) // { currentFile: '', percent: 100 });// 将 arrayBuffer 形式压的缩包数据写入二进制文件,生成 zipprogress({ percent: 0, msg: `保存 ZIP...` }); // 开始// 分块写入await appendFile({ filePath: zipPath, data: content.buffer, encoding: 'binary', progress: percent => progress({ percent: Math.floor(percent), msg: `保存 ZIP...` })}).then(() => {progress({ percent: 100, msg: `ZIP 保存完成` });}).catch(err => {console.error('写入文件失败:', err); });} catch (err) {console.log(err);}
}
追加写入文件
/*** 追加写入文件* @param {string} filePath 文件路径* @param {string} data 写入数据* @param {string} encoding 编码类型:默认 utf8* @param {number} chunkSize 写入块大小:默认 1048576 字节* @param {function} progress 更新进度回调*/
function appendFile(options) { let { filePath, data, encoding, chunkSize, progress } = Object.assign({encoding: 'utf8', // 编码类型,默认 utf8。想写二进制用 'binary'chunkSize: 1048576, // 每块大小默认 1Mprogress: console.log // 更新进度}, options);// 文件总长度const fileLength = data instanceof ArrayBuffer ? data.byteLength : data.length; // 文件小于 chunkSize 直接写if(fileLength <= chunkSize){return new Promise((resolve, reject) => {try {resolve(fs.writeFileSync( filePath, data, encoding ));} catch (error) {reject(error);} });}else{// 否则分块写入,并调用进度更新 callbackreturn new Promise((resolve, reject) => {// 先写入一个空文件。(作用:有则清空,无则创建)fs.writeFileSync(filePath, new ArrayBuffer(0), encoding);// 已写入长度let writtenLength = 0;// 写入数据块const writeChunk = () => {const chunkData = data.slice(writtenLength, writtenLength + chunkSize); // 切段fs.appendFile({ filePath, // 文件路径data: chunkData, // 数据块encoding, // 编码类型success: () => { writtenLength += chunkSize; // 更新已写入长度progress( Math.floor((writtenLength / fileLength) * 100)); // call回调函数更新进度 if (writtenLength < fileLength) { writeChunk(); // 继续写入下一块数据 } else { resolve(writtenLength); // 文件写入完成:返回写入长度} }, fail: err => reject(err) }); };// 继续调用写入数据块writeChunk(); });}
}
测试方法
test(){const zipFolder = `${wx.env.USER_DATA_PATH}/test`;const zipPath = `${zipFolder}/hello.zip`;let fileList = [];try {// 先创建对应目录fileUtil.mkdir(zipFolder);// 生成测试文件for (let index = 0; index < 10; index++){let filePath = `${wx.env.USER_DATA_PATH}/test/hello${index}.txt`;fileList.push({ name: `hello${index}.txt`, path: filePath});const res = fs.writeFileSync( filePath, `测试数据${index+1}`, 'utf8' );console.log(res);}// 打包 zipfileUtil.zip(fileList, zipPath, console.log);// 保存 zipwx.saveFileToDisk({ filePath: zipPath, success: console.log, fail: console.error });} catch(e) {console.error(e)}}
参考资料
jszip:一个使用JavaScript创建、读取和编辑.zip文件的库,带有一个可爱而简单的API。