JS前端解壓zip的方法和技巧分享
業(yè)務(wù)中有時(shí)候需要獲取某個(gè) zip
壓縮包內(nèi)的文件內(nèi)容展示到前端,在 zip
包體積不是那么大的時(shí)候(幾MB、十幾MB甚至幾十MB)并且不涉及壓縮包解密的時(shí)候,可以考慮純前端方案。
前端使用Jszip解壓zip
安裝依賴(lài): npm i jszip
請(qǐng)求 zip
文件并轉(zhuǎn)為 Blob
:
const blob = await fetch(url).then((res) => res.blob());
使用 jszip
解壓 Blob
:
const zip = new JSZip() const zipData = await zip.loadAsync(zipBlob)
這時(shí)候你會(huì)得到一個(gè)含有 files
列表數(shù)據(jù)的 zipData
, 這個(gè) files
就是壓縮包中的文件列表,這時(shí)候的處理就有意思了,下面慢慢說(shuō)。
如果你的壓縮包里面不止一個(gè)文件怎么獲取
基于上一步,我們拿到了 files
文件列表,這時(shí)候如果我們的壓縮包里面有很多文件我們?cè)趺慈慷寄玫侥??我們就需要遞歸這個(gè)列表了:
async function extractNestedZip(zipBlob: Blob) { const zip = new JSZip() const zipData = await zip.loadAsync(zipBlob) const extractedFiles: { name: string, data: unkown }[] = [] // 遍歷 ZIP 文件中的所有文件 for (const [name, file] of Object.entries(zipData.files)) { extractedFiles.push({name, file}) } return extractedFiles }
但是事情往往沒(méi)有這么簡(jiǎn)單,比如壓縮包里面還有壓縮包怎么辦呢?
嵌套壓縮改咋處理
改良 extractNestedZip
方法:
async function extractNestedZip(zipBlob: Blob) { const zip = new JSZip() const zipData = await zip.loadAsync(zipBlob) const extractedFiles: { name: string, data: unkown }[] = [] // 遍歷 ZIP 文件中的所有文件 for (const [name, file] of Object.entries(zipData.files)) { if (name.endsWith('.zip') { // 如果是嵌套的壓縮包就繼續(xù)解壓 const nestedZipBlob = await file.async('blob') const nestedFiles = await extractNestedZip(nestedZipBlob) extractedFiles.push(...nestedFiles) } else { extractedFiles.push({name, file}) } } return extractedFiles }
我們現(xiàn)在解決了嵌套的問(wèn)題。如果壓縮包中有文件夾該怎么處理呢?嘗試過(guò)你會(huì)發(fā)現(xiàn)如果是文件夾,在 files
中對(duì)應(yīng)的數(shù)據(jù)就是空的,所以我們應(yīng)該過(guò)濾這種情況:
壓縮包中的文件夾要過(guò)濾
async function extractNestedZip(zipBlob: Blob) { const zip = new JSZip() const zipData = await zip.loadAsync(zipBlob) const extractedFiles: { name: string, data: unkown }[] = [] // 遍歷 ZIP 文件中的所有文件 for (const [name, file] of Object.entries(zipData.files)) { if (name.endsWith('.zip') { // 如果是嵌套的壓縮包就繼續(xù)解壓 const nestedZipBlob = await file.async('blob') const nestedFiles = await extractNestedZip(nestedZipBlob) extractedFiles.push(...nestedFiles) } else if (!name.endsWith('/')) { // 我們可以通過(guò)判斷文件名是否以/結(jié)尾來(lái)判斷這一項(xiàng)是否是文件夾 extractedFiles.push({name, file}) } } return extractedFiles }
現(xiàn)在看了好像一切都沒(méi)問(wèn)題了,但是我們最終的文件怎么讀到呢?
文本文件和二進(jìn)制文件要分別處理
如果壓縮包中只包含文本類(lèi)的文件,比如 .json
,.log
之類(lèi)的,就可以簡(jiǎn)單的用 file.async('text')
來(lái)獲取文件內(nèi)容,但是如果包含 .mp3
,.png
就要注意了,我們接下來(lái)優(yōu)化這些情況:
async function extractNestedZip(zipBlob: Blob) { const zip = new JSZip() const zipData = await zip.loadAsync(zipBlob) const extractedFiles: { name: string, data: string | Blob }[] = [] // 遍歷 ZIP 文件中的所有文件 for (const [name, file] of Object.entries(zipData.files)) { if (name.endsWith('.zip')) { // 如果文件是嵌套的 ZIP 文件,則遞歸解壓 const nestedZipBlob = await file.async('blob') const nestedFiles: { name: string, data: string | Blob }[] = await extractNestedZip(nestedZipBlob) extractedFiles.push(...nestedFiles) } else { // 如果文件不是 ZIP 文件,則處理 if (name.endsWith('.jpeg') || name.endsWith('.png') || name.endsWith('.mp3') || name.endsWith('.mp4')) { const blob = await file.async('blob') extractedFiles.push({ name, data: blob }) } else if (!name.endsWith('/')) { // 過(guò)濾掉文件夾 const fileData = await file.async('text') extractedFiles.push({ name, data: fileData }) } } } return extractedFiles }
我們這里舉了些例子,就是判斷文件名以什么結(jié)尾,如果是常見(jiàn)的媒體格式,就轉(zhuǎn)為 Blob
,不然就轉(zhuǎn)為字符串。這個(gè)方案就可以處理壓縮包中不同格式的問(wèn)題,最終我們就拿到了一個(gè) name
是表示壓縮包中文件名稱(chēng),data
是對(duì)應(yīng)文件內(nèi)容的列表了。
總結(jié)
在業(yè)務(wù)中需要前端場(chǎng)景解壓壓縮包是比較少見(jiàn)的,但是如果有這類(lèi)的場(chǎng)景我們就可以借助于 jszip
來(lái)做。這次分享的主要是拿到文件之后如何全部拿到壓縮包的所有內(nèi)容的技巧,大家如果有別的問(wèn)題,歡迎評(píng)論區(qū)溝通。
以上就是JS前端解壓zip的方法和技巧分享的詳細(xì)內(nèi)容,更多關(guān)于JS前端解壓zip的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
工作中比較實(shí)用的JavaScript驗(yàn)證和數(shù)據(jù)處理的干貨(經(jīng)典)
工作中比較實(shí)用的JavaScript驗(yàn)證和數(shù)據(jù)處理知識(shí)經(jīng)常會(huì)用到,下面小編通過(guò)查閱相關(guān)資料及日常記錄的知識(shí)分享到腳本之家平臺(tái),供大家參考2016-08-08JS基于面向?qū)ο髮?shí)現(xiàn)的多個(gè)倒計(jì)時(shí)器功能示例
這篇文章主要介紹了JS基于面向?qū)ο髮?shí)現(xiàn)的多個(gè)倒計(jì)時(shí)器功能,結(jié)合實(shí)例形式分析了javascript面向?qū)ο蠹皶r(shí)間操作相關(guān)技巧,需要的朋友可以參考下2017-02-02js實(shí)現(xiàn)發(fā)送驗(yàn)證碼后的倒計(jì)時(shí)功能
本文解決方案的基本思路是點(diǎn)擊就將按鈕設(shè)為disabled,然后根據(jù)cookie判斷是否設(shè)置過(guò)期時(shí)間,將手機(jī)利用ajax提交到后臺(tái)的發(fā)短信接口,就可以了2015-05-05使用BroadcastChannel進(jìn)行跨窗口通信的實(shí)例詳解
BroadcastChannel 提供了一種簡(jiǎn)單而有效的方式來(lái)實(shí)現(xiàn)同一瀏覽器環(huán)境下不同頁(yè)面或腳本之間的通信,對(duì)于需要跨窗口、標(biāo)簽頁(yè)或 iframe 同步數(shù)據(jù)的應(yīng)用場(chǎng)景,它是一種非常便捷的解決方案,本文介紹了如何使用 BroadcastChannel 進(jìn)行跨窗口通信,需要的朋友可以參考下2024-08-08javascript比較兩個(gè)日期相差天數(shù)的方法
這篇文章主要介紹了javascript比較兩個(gè)日期相差天數(shù)的方法,涉及javascript針對(duì)日期的轉(zhuǎn)換與比較的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07uniapp路由uni-simple-router實(shí)例詳解
uni-simple-router專(zhuān)為uniapp打造的路由器,和uniapp深度集成,這篇文章主要給大家介紹了關(guān)于uniapp路由uni-simple-router的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09javascript實(shí)現(xiàn)五星評(píng)分功能
這篇文章主要介紹了javascript實(shí)現(xiàn)五星評(píng)分功能,大家現(xiàn)在會(huì)見(jiàn)到許多五星評(píng)級(jí),知道是如何實(shí)現(xiàn)的嗎?文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2015-11-11滾動(dòng)條響應(yīng)鼠標(biāo)滑輪事件實(shí)現(xiàn)上下滾動(dòng)的js代碼
javascript實(shí)現(xiàn)滾動(dòng)條響應(yīng)鼠標(biāo)滑輪的實(shí)現(xiàn)上下滾動(dòng),示例代碼如下2014-06-06