前端预览zip包信息
Source Code
ts
/**
* zip 格式参考:https://blog.csdn.net/a200710716/article/details/51644421
* @param {*} file
*/
function loadZipAsync(file) {
return new Promise(function(resolve, reject) {
const reader = new FileReader()
reader.addEventListener('load', function(event) {
const buffer = event.target.result as Buffer
const unit8Array = new Uint8Array(buffer)
try {
const comment = readEndOfCentral(unit8Array)
resolve(comment)
} catch (error) {
reject(error)
}
})
reader.addEventListener('error', (error) => {
reject(error)
})
reader.readAsArrayBuffer(file)
})
}
function readEndOfCentral(data) {
const offset = lastIndexOfSignature(data, 'PK\x05\x06')
if (offset === -1) {
throw new Error('does not find the end of central directory')
}
let startIndex = offset + 20
const commentLenSize = 2
const zipCommentLength = readInt(data, startIndex, commentLenSize)
if (!zipCommentLength) {
return null
}
startIndex += commentLenSize
const zipComment = data.slice(startIndex, startIndex + zipCommentLength)
const zipCommentStr = decodeFile(zipComment)
return zipCommentStr
}
function lastIndexOfSignature(data, sig) {
const sig0 = sig.charCodeAt(0),
sig1 = sig.charCodeAt(1),
sig2 = sig.charCodeAt(2),
sig3 = sig.charCodeAt(3)
for (let i = data.length - 4; i >= 0; i--) {
if (data[i] === sig0 && data[i + 1] === sig1 && data[i + 2] === sig2 && data[i + 3] === sig3) {
return i
}
}
return -1
}
/**
* Get the next number with a given byte size.
* @param {number} size the number of bytes to read.
* @return {number} the corresponding number.
*/
function readInt(data, startIndex, size) {
let result = 0,
i
for (i = startIndex + size - 1; i >= startIndex; i--) {
result = (result << 8) + data[i]
}
return result
}
// 获取字符编码对应字符的字节长度(比如汉字是 2 个字节,ascii 是 1 个字节)
const _utf8len = (function() {
const _utf8len = new Array(256)
for (let i = 0; i < 256; i++) {
_utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1)
}
_utf8len[254] = _utf8len[254] = 1 // Invalid sequence start
return _utf8len
})()
function decodeFile(buf) {
let str, i, out, c, c_len
const len = buf.length
// Reserve max possible length (2 words per char)
// NB: by unknown reasons, Array is significantly faster for
// String.fromCharCode.apply than Uint16Array.
let utf16buf = new Array(len * 2)
for (out = 0, i = 0; i < len;) {
c = buf[i++]
// quick process ascii
if (c < 0x80) { utf16buf[out++] = c; continue }
c_len = _utf8len[c]
// skip 5 & 6 byte codes
if (c_len > 4) {
utf16buf[out++] = 0xfffd
i += c_len - 1
continue
}
// apply mask on first byte
c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07
// join the rest
while (c_len > 1 && i < len) {
c = (c << 6) | (buf[i++] & 0x3f)
c_len--
}
// terminated by end of string?
if (c_len > 1) { utf16buf[out++] = 0xfffd; continue }
if (c < 0x10000) {
utf16buf[out++] = c
} else {
c -= 0x10000
utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff)
utf16buf[out++] = 0xdc00 | (c & 0x3ff)
}
}
// shrinkBuf(utf16buf, out)
if (utf16buf.length !== out) { // 含有 utf8 字符
if (utf16buf.subarray) {
utf16buf = utf16buf.subarray(0, out)
} else {
utf16buf.length = out
}
}
return String.fromCharCode.apply(null, utf16buf)
}
export default loadZipAsync
Useage
ts
loadZipAsync(uploadFile.raw).then((res: string) => {
console.log('包信息:', res)
}).catch((err) => {
console.log('包解析错误!')
})