文件上传
更新: 2025/3/12 17:59:43 字数: 0 字
文件切片
在做 知识图谱
时,需要上传对应的音乐的视频文件,但是文件太大了,大部分都在 500MB
以上,所以需要分片上传。
ts
import { cutFile } from'./cutFile.js';
const inpFile = document.querySelector('input[type="file"]');
// 选择文件后会触发的 onchange 事件
inpFile.onchange = async(e) =>{
const file = e.target.files[o];
console.time('cutFile');
const chunks= await cutFile(file);
console.timeEnd('cutFile');
console.log(chunks);
};
cutFile
函数主要来将文件进行分片,返回的是一个数组,数组中的每个元素都是一个分片,分片大小为 5MB
。
ts
// cutFile.js
const CHUNK_SIZE = 1024 * 1024 * 5;
const THREAD_COUNT = navigator.hardwareConcurrency || 4;
// 分片是耗时任务,我们可以将其放到 worker 中执行,这样不会阻塞主线程
/**
* 将文件进行分片
* @param file
*/
export async function cutFile(file: any) {
return new Promise((resolve) => {
let result: any = []
const chunkCount = Math.ceil(file.size / CHUNK_SIZE);
// 每一个线程需要处理的分片数量
const workerChunksCount = Math.ceil(chunkCount / THREAD_COUNT);
let finishCount = 0;
for (let i = 0; i < THREAD_COUNT; i++) {
const worker = new Worker("../worker.js", {
type: "module",
})
// 线程开始索引
const startIndex = i * workerChunksCount;
const endIndex = startIndex + workerChunksCount;
worker.postMessage({
file,
chunkSize: CHUNK_SIZE,
startIndex: startIndex,
endIndex: endIndex,
})
worker.onmessage = (e) => {
for (let i = startIndex; i < endIndex; i++){
return[i] = e.data[i - startIndex];
}
worker.terminate()
finishCount++;
if(finishCount === THREAD_COUNT){
resolve(result)
}
}
}
})
}
worker.js
文件中,主要就是将文件进行分片,并且计算出对应的 MD5
值,然后将分片和 MD5
值一起返回。
ts
import {createChunk} from "./createChunk.ts";
onmessage = async (e) => {
const {file, startIndex, endIndex, chunkSize} = e.data
const prams = []
for (let i = startIndex; i <= endIndex; i++) {
prams.push(createChunk(file, i, chunkSize))
}
const result = await Promise.all(prams)
postMessage(result)
}
ts
import SparkMD5 from "./sparkmd5.js"
// SparkMD5 可以去 github 上下载
/**
* 创建分片
* @param file 传入的文件
* @param index 第几个分片
* @param chunkSize 分片大小
*/
export function createChunk(file: any, index: any, chunkSize: any) {
return new Promise((resolve) => {
const start = index * chunkSize; // 开始位置
const end = start + chunkSize // 结束位置
const spark: any = new SparkMD5.ArrayBuffer(); // 创建md5对象
const fileReader = new FileReader(); // 创建文件读取对象
fileReader.onload = function (e: any) {
spark.append(e.target.result); // 将文件内容添加到md5对象中
resolve({
start,
end,
index,
hash: spark.end(), // 获取md5值
});
}
fileReader.readAsArrayBuffer(file.slice(start, end));
})
}
web work 使用
web worker
是一种异步执行代码的方式,它可以在浏览器中运行,并且不会阻塞主线程,从而提高性能。
WebWork
在 html
中使用方法:
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebWork</title>
</head>
<body> </body>
<script>
// 直接创建 work.js 文件
var work = new Worker('./work.js')
work.postMessage(1000000000)
work.onmessage = function(res){
console.log("累加结果 : ",res.data)
}
</script>
</html>
js
onmessage = function (e) {
let sum = 0, num = e.data;
for (var i = 1; i <= num; i++) {
sum += i
}
postMessage(sum);
}
在 react 中使用 web worker
ts
// index.tsx
const worker = new Worker('./worker.ts')
web worker
需要指定一个脚本的 URI
,而在 React
的实际项目中,我们一般都会和打包工具一起使用(比如:webpack
),这时如果直接引用文件,就会发生错误。
如果使用 webpack
,可以通过 worker-loader
来解决,配置如下:
js
{
module: {
rules: [
{
test: /\.worker\.ts$/,
use: [
{
loader: 'worker-loader',
options: {
inline: 'fallback',
},
},
{
loader: 'ts-loader',
},
],
}
]
}
}
worker-loader
会把文件加载为 web worker
,我们只需要把文件名命名为 /\.worker\.ts$/
格式,比如 msg.worker.ts