Last active
January 29, 2023 18:55
-
-
Save semlinker/3bb9634f4e4ec7b6ab4008a688583115 to your computer and use it in GitHub Desktop.
在线解压ZIP文件
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const path = require("path"); | |
const Koa = require("koa"); | |
const cors = require("@koa/cors"); | |
const Router = require("@koa/router"); | |
const StreamZip = require("node-stream-zip"); | |
const app = new Koa(); | |
const router = new Router(); | |
const ZIP_HOME = path.join(__dirname, "zip"); | |
const UnzipCaches = new Map(); | |
router.get("/", async (ctx) => { | |
ctx.body = "服务端在线解压ZIP文件示例(阿宝哥)"; | |
}); | |
router.get("/unzip/:name", async (ctx) => { | |
const fileName = ctx.params.name; | |
let filteredEntries; | |
try { | |
if (UnzipCaches.has(fileName)) { | |
// 优先从缓存中获取 | |
filteredEntries = UnzipCaches.get(fileName); | |
} else { | |
const zip = new StreamZip.async({ file: path.join(ZIP_HOME, fileName) }); | |
const entries = await zip.entries(); | |
filteredEntries = Object.values(entries).map((entry) => { | |
return { | |
name: entry.name, | |
size: entry.size, | |
dir: entry.isDirectory, | |
}; | |
}); | |
await zip.close(); | |
UnzipCaches.set(fileName, filteredEntries); | |
} | |
ctx.body = { | |
status: "success", | |
entries: filteredEntries, | |
}; | |
} catch (error) { | |
ctx.body = { | |
status: "error", | |
msg: `在线解压${fileName}文件失败`, | |
}; | |
} | |
}); | |
router.get("/unzip/:name/entry", async (ctx) => { | |
const fileName = ctx.params.name; | |
const entryPath = ctx.query.path; | |
try { | |
const zip = new StreamZip.async({ file: path.join(ZIP_HOME, fileName) }); | |
const entryData = await zip.entryData(entryPath); | |
await zip.close(); | |
ctx.body = { | |
status: "success", | |
entryData: entryData, | |
}; | |
} catch (error) { | |
console.dir(error); | |
ctx.body = { | |
status: "error", | |
msg: `读取${fileName}中${entryPath}文件失败`, | |
}; | |
} | |
}); | |
// 注册中间件 | |
app.use(cors()); | |
app.use(router.routes()).use(router.allowedMethods()); | |
app.listen(3000, () => { | |
console.log("app starting at port 3000"); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="zh-cn"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>浏览器在线解压ZIP</title> | |
<script src="https://cdn.bootcdn.net/ajax/libs/jszip/3.5.0/jszip.min.js"></script> | |
<script src="https://cdn.bootcdn.net/ajax/libs/jszip-utils/0.1.0/jszip-utils.min.js"></script> | |
<style> | |
.caret { | |
cursor: pointer; | |
-webkit-user-select: none; /* Safari 3.1+ */ | |
-moz-user-select: none; /* Firefox 2+ */ | |
-ms-user-select: none; /* IE 10+ */ | |
user-select: none; | |
} | |
.caret::before { | |
content: "\25B6"; | |
color: black; | |
display: inline-block; | |
margin-right: 6px; | |
} | |
.caret-down::before { | |
-ms-transform: rotate(90deg); /* IE 9 */ | |
-webkit-transform: rotate(90deg); /* Safari */' | |
transform: rotate(90deg); | |
} | |
.indent { | |
text-indent: 1em; | |
} | |
#fileList > li { | |
list-style: none; | |
} | |
</style> | |
</head> | |
<body> | |
<p> | |
<label>请输入ZIP文件的线上地址:</label> | |
<input type="text" id="zipUrl" /> | |
</p> | |
<button id="unzipBtn" onclick="unzipOnline()">在线解压</button> | |
<p id="status"></p> | |
<ul id="fileList"></ul> | |
<script> | |
class ExeJSZip { | |
// 用于获取url地址对应的文件内容 | |
getBinaryContent(url, progressFn = () => {}) { | |
return new Promise((resolve, reject) => { | |
if (typeof url !== "string" || !/https?:/.test(url)) | |
reject(new Error("url 参数不合法")); | |
JSZipUtils.getBinaryContent(url, { | |
// JSZipUtils来自于jszip-utils这个库 | |
progress: progressFn, | |
callback: (err, data) => { | |
if (err) { | |
reject(err); | |
} else { | |
resolve(data); | |
} | |
}, | |
}); | |
}); | |
} | |
// 遍历Zip文件 | |
async iterateZipFile(data, iterationFn) { | |
if (typeof iterationFn !== "function") { | |
throw new Error("iterationFn 不是函数类型"); | |
} | |
let zip; | |
try { | |
zip = await JSZip.loadAsync(data); // JSZip来自于jszip这个库 | |
zip.forEach(iterationFn); | |
return zip; | |
} catch (error) { | |
throw new error(); | |
} | |
} | |
} | |
</script> | |
<script> | |
const zipUrlEle = document.querySelector("#zipUrl"); | |
const statusEle = document.querySelector("#status"); | |
const fileList = document.querySelector("#fileList"); | |
const exeJSZip = new ExeJSZip(); | |
async function unzipOnline() { | |
fileList.innerHTML = ""; | |
statusEle.innerText = "开始下载文件..."; | |
const data = await exeJSZip.getBinaryContent( | |
zipUrlEle.value, | |
handleProgress | |
); | |
let items = ""; | |
await exeJSZip.iterateZipFile(data, (relativePath, zipEntry) => { | |
items += `<li class=${zipEntry.dir ? "caret" : "indent"}>${ | |
zipEntry.name | |
}</li>`; | |
}); | |
statusEle.innerText = "ZIP文件解压成功"; | |
fileList.innerHTML = items; | |
} | |
function handleProgress(progressData) { | |
const { percent, loaded, total } = progressData; | |
if (loaded === total) { | |
statusEle.innerText = "文件已下载,努力解压中"; | |
} | |
} | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="zh-cn"> | |
<head> | |
<meta charset="UTF-8" /> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
<title>服务器在线解压Zip</title> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> | |
<style> | |
.caret { | |
cursor: pointer; | |
-webkit-user-select: none; /* Safari 3.1+ */ | |
-moz-user-select: none; /* Firefox 2+ */ | |
-ms-user-select: none; /* IE 10+ */ | |
user-select: none; | |
} | |
.caret::before { | |
content: "\25B6"; | |
color: black; | |
display: inline-block; | |
margin-right: 6px; | |
} | |
.caret-down::before { | |
-ms-transform: rotate(90deg); /* IE 9 */ | |
-webkit-transform: rotate(90deg); /* Safari */' | |
transform: rotate(90deg); | |
} | |
.indent { | |
text-indent: 1em; | |
} | |
#fileList > li { | |
list-style: none; | |
} | |
</style> | |
</head> | |
<body> | |
<p> | |
<label>请输入ZIP文件名:</label> | |
<input type="text" id="fileName" value="kl_161828427993677" /> | |
</p> | |
<button id="unzipBtn" onclick="unzipOnline()">在线解压</button> | |
<p id="status"></p> | |
<ul id="fileList"></ul> | |
<script> | |
const fileList = document.querySelector("#fileList"); | |
const fileNameEle = document.querySelector("#fileName"); | |
const request = axios.create({ | |
baseURL: "http://localhost:3000/", | |
timeout: 5000, | |
}); | |
async function unzipOnline() { | |
const fileName = fileNameEle.value; | |
if(!fileName) return; | |
const response = await request.get(`unzip/${fileName}`); | |
if (response.data && response.data.status === "success") { | |
const entries = response.data.entries; | |
let items = ""; | |
entries.forEach((zipEntry) => { | |
items += `<li class=${zipEntry.dir ? "caret" : "indent"}>${ | |
zipEntry.name | |
}</li>`; | |
}); | |
fileList.innerHTML = items; | |
} | |
} | |
async function previewZipFile(path = "minivue-master/img/structure.png") { | |
const fileName = fileNameEle.value; | |
const response = await request.get( | |
`unzip/${fileName}/entry?path=${path}` | |
); | |
if (response.data && response.data.status === "success") { | |
const { entryData } = response.data; | |
const entryBuffer = toArrayBuffer(entryData.data); | |
const blob = new Blob([entryBuffer]); | |
// 使用URL.createObjectURL或blob.text()读取文件信息 | |
} | |
} | |
function toArrayBuffer(buf) { | |
let ab = new ArrayBuffer(buf.length); | |
let view = new Uint8Array(ab); | |
for (let i = 0; i < buf.length; ++i) { | |
view[i] = buf[i]; | |
} | |
return ab; | |
} | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
,,