背景
文件上传功能在中后台项目中是最常见的功能,分片上传是一种将大文件分割成多个小片段进行上传的技术,可以有效提高文件上传的速度和稳定性。
思路
1.首先就是使用File.slice对文件进行分割产出一个数组用于存储每个小的chunk片段
2.异步计算hash值,可用作标识文件进而实现文件的断点续传、秒传等功能,这里我们采用spark-MD5计算文件hash值
3.在计算hash的时候,特别是文件比较大的时候就会明显感觉应用卡顿,所以采用webworker的方式另外开一个线程去计算文件hash值
实现
本文基于vue作简单实现
1.简单布局-主要是一个input标签,加上用于展示当前计算hash值的进度。
<template> <div> <div> <input @change="handleChange" ref="inputRef" type="file" />选择文件 </div> 当前计算hash百分比进度<h1 style="color:#fff">{{ precentageRef }}%</h1> </div> </template>
2.创建切片功能函数
const createFileChunk = (file, size = 1024 * 20) => { //可根据传入尺寸确定单个chunk大小 const chunk = []; for (let i = 0; i < file.size; i += size) { chunk.push(file.slice(i, i + size)); } return chunk; };
3.创建hash读取函数
const createHash = async (file) => { //采用异步读取,主要将file传给worker读取 return new Promise((resolve) => { const myWorker = new Worker(); // 创建worker myWorker.postMessage({ file });//将要读取hash的文件传给worker myWorker.onmessage = (e) => {//读取的过程,用onmessage监听,可以设置读取进度百分比 const {percentage,hash}=e.data precentageRef.value=percentage//将百分比实时展示 if(percentage>=100){//如果到了100%代表已经读取完毕,就resolve出去 resolve(hash) } }; }); };
4.创建worker读取文件hash
import SparkMD5 from 'spark-md5' let percentage = 0;//初始化百分比 self.onmessage = (e) => { const { file } = e.data;//拿到传过来的文件 const spark = new SparkMD5(); function _read(index) {//index为读取的文件chunk下标 let fileReader = new FileReader();//创建fileReader对文件chunk进行数据读写,并将内容拿给sparkMD5计算hash fileReader.readAsArrayBuffer(file[index]); fileReader.onload = (e) => { spark.append(e.target.result) if (index >= file.length-1) {//如果读取完毕就向外发送读取完毕消息 self.postMessage({ hash: spark.end(), percentage:100 }); } else {//否则递归读取下一个chunk percentage+=100/file.length self.postMessage({ hash: 'pending', percentage:percentage }); _read(index + 1); } }; } _read(0); };
这就是文件分片以及异步计算hash的简化流程。
完整代码:
fileLoader.vue
<template> <div> <div> <input @change="handleChange" ref="inputRef" type="file" />选择文件 </div> 当前计算hash百分比进度<h1 style="color:#fff">{{ precentageRef }}%</h1> </div> </template> <script setup> import Worker from '../worker.js?worker' import {ref} from 'vue' const precentageRef=ref(0) const handleChange = async (e) => { const { files } = e.target; if(!files)return let c = createFileChunk(files[0],1024*1024); const hash = await createHash(c); if (hash) { console.log(c, hash); } }; const handleClick=()=>{ alert(1) } const createFileChunk = (file, size = 1024 * 20) => { const chunk = []; for (let i = 0; i < file.size; i += size) { chunk.push(file.slice(i, i + size)); } return chunk; }; const createHash = async (file) => { return new Promise((resolve) => { const myWorker = new Worker(); // 创建worker myWorker.postMessage({ file }); myWorker.onmessage = (e) => { console.log(e.data); const {percentage,hash}=e.data precentageRef.value=percentage if(percentage>=100){ resolve(hash) } }; // Greeting from Worker.js,worker线程发送的消息 }); }; </script> <style lang="scss" scoped></style>
worker.js
import SparkMD5 from 'spark-md5' let percentage = 0; self.onmessage = (e) => { const { file } = e.data; const spark = new SparkMD5(); function _read(index) { let fileReader = new FileReader(); console.log(index,file.length,file,file[index]) fileReader.readAsArrayBuffer(file[index]); fileReader.onload = (e) => { spark.append(e.target.result); if (index >= file.length-1) { self.postMessage({ hash: spark.end(), percentage:100 }); } else { percentage+=100/file.length self.postMessage({ hash: 'pending', percentage:percentage.toFixed(2) }); _read(index + 1); } }; } _read(0); };
效果:UI界面比较low!!!
标签:异步,const,index,chunk,file,分片,hash,percentage From: https://www.cnblogs.com/micbin/p/17672435.html