前言
大家好,好久没更新了,这主要是因为我最近懈怠了,没咋学习,其次这段时间公司里面也挺忙的,经常加班,导致我回家只想着打打游戏,五一假期我在练车,也没学习,最近稍微好点,有开始学习,不过是在看英语,我这个人就是学习兴趣一阵一阵的,啥都想学一点,啥也不是很精,有机会得好好做个规划,废话不多说,今天给大家介绍一下jszip压缩文件夹的方式,这是我公司的需求啊,之前只是让我把文件展开上传就行了,现在居然要保留原先的目录结构,真的需求越来越离谱,能咋办,整呗
前置代码
基础架子我还是用之前我写过的jszip压缩的代码。
参考地址:https://myblog-5g89ixpbbf1fbfad-1316695488.ap-shanghai.app.tcloudbase.com/2024/04/09/jszip-study/
纠错
我之前写的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const getFileSize = (size) => { let initNum = 0; const unit = ["Bytes", "KB", "MB", "GB", "TB"]; const returnValFunc = () => { return size.toFixed(2) + " " + unit[initNum]; }; if (size <= 1000) { return returnValFunc(); }
while (size > 1024) { size /= 1024; initNum++; } return returnValFunc(); };
|
这里面的size/=1000这个代码是不需要的,加了反而导致进制报错
列表展示修改
首先就是我们列表展示要进行修改,不能将文件直接展开了,需要将文件夹的名称作为一行进行push
我们先来看一下逻辑,就是handleFileFolderAdd
函数的表层逻辑应该是变成这样
1 2 3 4 5 6 7 8 9 10
| if(fileEntry.isDirectory){ let curNeedAddFolder={ name:fileEntry.name, size:0, time:new Date().toLocaleString(), } this.fileList.push(curNeedAddFolder) }
|
但是这样也会有一个问题,size没了,所以我们还是需要之前的展开逻辑,将size进行累加计算,因此我将代码改成了这样,这里通过闭包和async await以及promise来实现了异步递归循环函数的处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| const readEntriesAsync = (reader) => new Promise((resolve) => { reader.readEntries((results) => { const cacheRes = results.map((item) => ({ entry: item, })); resolve(cacheRes); }); });
const fileEntriesToFiles = (entrie) => new Promise((resolve)=>{ entrie.file((file)=>{ resolve(file); }) })
const handleFileFolderAdd = (items) => { for (let j = 0; j < items.length; j++) { const item = items[j]; const fileEntry = item.webkitGetAsEntry(); let totalSize = 0; if (fileEntry.isDirectory) { const reader = fileEntry.createReader(); let curNeedAddFolder = { name: fileEntry.name, size: 0, time: new Date().toLocaleString(), }; const readEntries = async (reader) => { return new Promise(async (resolve, reject) => { const readEntriesRecursive = async (reader) => { try { const results = await readEntriesAsync(reader); for (let i = 0; i < results.length; i++) { const curItem = results[i]; const curFileEntry = curItem.entry; if (curFileEntry.isFile) { const file=await fileEntriesToFiles(curFileEntry) totalSize += file.size; } else { await readEntries(curFileEntry.createReader()); } } console.log(totalSize, "totalSize") resolve(totalSize); } catch (e) { console.error(e, "e"); reject(e); } }; await readEntriesRecursive(reader); }); }; readEntries(reader).then((totalSize) => { fileList.value.push({ ...curNeedAddFolder, size: totalSize, }); }); } else if (fileEntry.isFile) { fileEntry.file((file) => { handleFileAdd([file]); }); } } };
|
此时效果如下
根目录fileEntry处理
这样,我们页面上的显示的确没问题了,但是这个文件夹,里面没有关联一点和文件内容相关的东西,这样肯定是有问题的。接下来我们将根目录的fileEntry也给push到fileList当中,以便后续的zip操作。
将返回不用entrie包一层
当时我这么做是因为之前写的时候公司有另外的需求,有参数处理,这里,咱们按照简单的来
1 2 3 4 5 6 7
| const readEntriesAsync = (reader) => new Promise((resolve) => { reader.readEntries((results) => { resolve(results); }); });
|
把第一次entries进行push
这里我加了个判断,如果是第一次处理文件夹目录的,将它的entries赋值给rootEntries,然后在最后push的时候给加到fileList里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| const handleFileFolderAdd = (items) => { for (let j = 0; j < items.length; j++) { const item = items[j]; const fileEntry = item.webkitGetAsEntry(); let totalSize = 0; if (fileEntry.isDirectory) { const reader = fileEntry.createReader(); let curNeedAddFolder = { name: fileEntry.name, size: 0, time: new Date().toLocaleString(), }; let isRoot = true; let rootEntries = []; const readEntries = async (reader) => { return new Promise(async (resolve, reject) => { const readEntriesRecursive = async (reader) => { try { const results = await readEntriesAsync(reader); if (isRoot) { rootEntries = results; isRoot = false; } for (let i = 0; i < results.length; i++) { const curFileEntry = results[i]; if (curFileEntry.isFile) { const file = await fileEntriesToFiles(curFileEntry); totalSize += file.size; } else { await readEntries(curFileEntry.createReader()); } } console.log(totalSize, "totalSize"); resolve(totalSize); } catch (e) { console.error(e, "e"); reject(e); } }; await readEntriesRecursive(reader); }); }; readEntries(reader).then((totalSize) => { console.log(rootEntries, "rootEntries"); fileList.value.push({ ...curNeedAddFolder, size: totalSize, fileEntry: rootEntries, }); }); } else if (fileEntry.isFile) { fileEntry.file((file) => { handleFileAdd([file]); }); } } };
|
此时我们看一下,我们将entry给加进去了
压缩列表处理
这里我用到了jszip打包文件夹的方法,zip.folder
这里需要传个文件名进去,然后后续属于这个文件夹的内容我们只需要将文件塞进去就行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| const zip = ref(null);
const addFolderToZip = async (folderPath, folder) => { return new Promise((resolve, reject) => { const handleFolderToZip = async (folderPath, folder) => { try { for (let i = 0; i < folder.length; i++) { const item = folder[i]; if (item.isFile) { const file = await fileEntriesToFiles(item); zip.value.file(folderPath + "/" + file.name, file); } else if (item.isDirectory) { zip.value.folder(folderPath + "/" + item.name); const results = await readEntriesAsync(item.createReader()); await addFolderToZip(folderPath + "/" + item.name, results); } } resolve(); } catch (e) { reject(e); } }; handleFolderToZip(folderPath, folder); }); };
const handleZipFileList = () => { return new Promise(async (resolve) => { for (let i = 0; i < fileList.value.length; i++) { const file = fileList.value[i]; if (!file.fileEntry || file.isFile) { const blob = new Blob([file], { type: file.type }); zip.value.file(file.name, blob, { binary: true }); } else { zip.value.folder(file.name); await addFolderToZip(file.name, file.fileEntry); } } resolve(zip.value); }); };
const handlePackageFileList = () => { if (fileList.value.length === 0) { MessagePlugin.error("请先上传文件"); return; } zip.value = new JSZip(); handleZipFileList().then(() => { console.log(zip.value, "zip.value"); zip.value .generateAsync({ type: "blob", }) .then((content) => { const fils = new File([content], `${fileList.value[0].name}.zip`, { type: "zip", }); const url = URL.createObjectURL(fils); const a = document.createElement("a"); a.href = url; a.download = `${fileList.value[0].name}.zip`; a.click(); URL.revokeObjectURL(url); }); }); };
|
此时效果如下
结语
到这里,我们的功能就完成了,这里需要注意一个细节就是for循环不能用foreach替换,会产生bug。更多内容敬请期待,债见~