Files
hexo-blog/source/_posts/浏览器端crc32文件计算以及分片上传思路.md
T
2021-03-05 16:01:24 +08:00

134 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: 浏览器端crc32文件计算以及分片上传思路
id: '362'
cover: '/images/AAAABSGsf8u86EvIjRhj.jpg'
categories:
- 分享
tags:
- JavaScript
- html
- crc32
- 浏览器
- 分片上传
date: 2020-12-27 15:21:00
---
大文件上传我们知道需要做MD5计算以及文件分片,由于最近业务业务上的调整,需要把MD5换成crc32,,crc32可以校验文件的完整性,对于业务处理比较方便。这里记录一下解决思路吧。
# 1. 文件分片
考虑到文件可能很大,出于性能的考虑,优先把文件分片,这里我设置默认5M大小一个分片:
``` js
const createFileChunk = (file, size = 5 * 1024 * 1024) => {
let chunks = [];
let cur = 0;
while (cur < file.size) {
chunks.push(file.slice(cur, cur + size));
cur += size;
}
return chunks;
};
```
# 2. 文件crc32计算
首先找一个crc32的库,这里我选了sheetjs的[crc32](https://github.com/SheetJS/js-crc32)库。
为了提高性能,这种纯计算的功能使用web workers另起一个线程处理。
``` js
// crc32_worker.js
// 引入crc32.js库,importScripts只支持url引入
self.importScripts("https://cdn.bootcdn.net/ajax/libs/crc-32/1.2.0/crc32.js");
// 生成文件 hash
self.onmessage = e => {
const {
fileChunks
} = e.data;
let crc32 = null;
let percentage = 0;
let count = 0;
const loadNext = index => {
const reader = new FileReader();
reader.readAsArrayBuffer(fileChunks[index]);
reader.onload = e => {
count++;
const blob = new Uint8Array(e.target.result);
if (index === 0) {
crc32 = self.CRC32.buf(blob);
} else {
crc32 = self.CRC32.buf(blob, crc32);
}
if (count === fileChunks.length) {
self.postMessage({
percentage: 100,
hash: crc32
});
self.close();
} else {
percentage += 100 / fileChunks.length;
self.postMessage({
percentage
});
loadNext(count);
}
};
};
loadNext(0);
};
```
web workers调用以及封装:
``` js
// 计算文件 crc32(web-worker)参数为上面分片后返回的chunks
const createFileCRC32InWorker = fileChunks => {
return new Promise(resolve => {
// 引入上面的worker文件
const worker = new Worker("./crc32_worker.js");
worker.postMessage({
fileChunks
});
worker.onmessage = e => {
// 这边加了进度条 这里的进度条,看需要显示
const {
percentage,
hash
} = e.data;
hash && resolve(hash);
};
});
};
```
# 3. 上传进度本地缓存
计算出的crc32值用来作为判断文件的key,可在localStorage缓存分片上传的进度。
``` js
const uploadCache = {
1259060791: {
position: [0, 0, 0]
}
}
```
如上代码, ` 1259060791 ` 为文件的crc32值,把它作为key, ` position ` 为上传的进度,比如一个15M的文件,会分成3片(默认设置了每片5M),然后根据自己的上传业务,上传完成的分片标记为 ` 1 ` 。
``` js
const uploadCache = {
1259060791: {
position: [1, 0, 0] // 第一片上传完成后标记为1
}
}
```
值得注意的是,通常分片上传都会多个分片并行上传,标记为 ` 1 ` 需要留意 ` position ` 的下标跟分片的下标是否一致。
# 4. 浏览器刷新后获取文件的问题
由于浏览器的安全机制,刷新后无法自动获取到原来的文件,所以需要通过提示去引导用户重现选择该文件,然后才可以断点续传。