vue读取本地文件踩坑
vue读取本地文件pako压缩
·
1.背景
最近在做web读取本地文件的时候遇到了一些坑,在此记录下
2.问题
2.1 window.showDirectoryPicker()需要在https条件下调试
设置vue.config.js 的配置项devServer.https 为true即可
2.2 遍历文件夹下文件
fileTypeFilter: [
{
fileType: '.json',
prefixLen: 29 // base64内容前面的长度
},
{
fileType: '.bin',
prefixLen: 37 // base64内容前面的长度
}
],
// 获取本地文件
async getLocalFile () {
const dirHandle = await window.showDirectoryPicker()
this.localFileList = []
this.dataStatus = common.LOCAL_DATA
let realRoot = dirHandle.name
if (realRoot == 'RawInfo') {
realRoot = 'client'
}
if (realRoot != '') {
this.getChild(dirHandle, realRoot, this.localFileList)
}
},
// 遍历文件夹获得所有文件的路径
async getChild (dirHandle, root, ret) {
if (dirHandle.kind != 'directory') {
return
}
for await (const entry of dirHandle.values()) {
if (entry.kind == 'directory') {
this.getChild(entry, root + '/' + entry.name, ret)
} else {
const file = await entry.getFile()
if (this.getFilePrefixLen(entry.name) != -1) {
ret.push(root + '/' + entry.name)
this.readFile(root + '/' + entry.name, file)
}
}
}
},
getFilePrefixLen (fileName) {
let len = -1
this.fileTypeFilter.forEach((value) => {
if (fileName.search(value.fileType) != -1) {
len = value.prefixLen
return
}
})
return len
},
2.3 读取文件时,onload为异步执行
注意,虽然bin文件用readAsDataURL也能读取到内容,但是试了几次了发现,bin文件中可能会有些字符在转换的时候有问题,比如出现 EF BF BD 等(这个是无效字符的替换)字符,其实对应过去只有一个字节,导致bin文件最终不一致,所以bin文件最好还是直接用readAsArrayBuffer 读取,然后直接用gzip进行压缩,这样就可以无损还原了
async readFile (fileName, file) {
let fileInfo = common.getFileInfo(fileName)
// bin文件用ArrayBuffer读取,防止有乱码出现
// json用dataUrl读取
let read = new FileReader();
if (fileName.indexOf(".bin") !== -1) {
read.readAsArrayBuffer(file);
} else {
read.readAsDataURL(file);
}
// read读取完毕回调
read.onload = (e) => {
// bin文件用
if (fileName.indexOf(".bin") !== -1) {
let buffer = new Uint8Array(read.result);
fileInfo.content = common.zip(buffer)
} else {
fileInfo.content = read.result.substr(
this.getFilePrefixLen(fileName),
read.result.length
)
fileInfo.content = common.zip(Base64.decode(fileInfo.content))
}
};
},
2.4 pako.js库使用
注意,此方法规避了pako压缩后中文乱码的问题,网上其他方法很多是有问题的,还有就是json压缩的问题,一般来说有几种方法,最简单的就是用
JSON.stringify
把格式(空格和换行)去掉, 另外就是采用压缩,比如pako
export function unzip (b64Data) {
let charData = atob(b64Data).split('').map(function (x) { return x.charCodeAt(0); });
let binData = new Uint8Array(charData);
return pako.inflate(binData, { to: 'string' });
}
export function zip (str) {
let binaryString = pako.gzip(str);
let a = Array.from(binaryString);
let s = "";
a.forEach((item, index) => {
s += String.fromCharCode(item)
})
return btoa(s)
}
后端go解压缩代码
// 内置包 "compress/gzip"
// gzip压缩
func GzipEncode(input []byte) ([]byte, error) {
// 创建一个新的 byte 输出流
var buf bytes.Buffer
// 创建一个新的 gzip 输出流
gzipWriter := gzip.NewWriter(&buf)
// 将 input byte 数组写入到此输出流中
_, err := gzipWriter.Write(input)
if err != nil {
_ = gzipWriter.Close()
return nil, err
}
if err := gzipWriter.Close(); err != nil {
return nil, err
}
// 返回压缩后的 bytes 数组
return buf.Bytes(), nil
}
// gzip解压缩
func GzipDecode(input []byte) ([]byte, error) {
// 创建一个新的 gzip.Reader
bytesReader := bytes.NewReader(input)
gzipReader, err := gzip.NewReader(bytesReader)
if err != nil {
return nil, err
}
defer func() {
// defer 中关闭 gzipReader
_ = gzipReader.Close()
}()
buf := new(bytes.Buffer)
// 从 Reader 中读取出数据
if _, err := buf.ReadFrom(gzipReader); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
更多推荐
已为社区贡献2条内容
所有评论(0)