直接看代码
<template>
<h1>大文件上传</h1>
<input type="file" @change="handleUpload">
</template>
<script setup>
import SparkMD5 from 'spark-md5'
const CHUNK_SIZE = 1024 * 1024; //1MB
const fileHash = ref('')
const fileName = ref('')
/** 文件分片 **/
const createChunks = (file) => {
let cur = 0;
let chunks = []
while (cur < file.size) {
const blob = file.slice(cur, cur + CHUNK_SIZE)
chunks.push(blob)
cur += CHUNK_SIZE
}
return chunks
}
/** hash计算 **/
const calculateHash = (chunks) => {
return new Promise(resolve => {
const targets = [] //存储参与计算的切片
const spark = new SparkMD5.ArrayBuffer()
const fileReader = new FileReader()
chunks.forEach((chunk, index) => {
// 第一个和最后一个切片参与计算
if (index === 0 || index === chunks.length - 1) {
targets.push(chunk)
} else {
// 中间的切片只计算前面两个字节 中间两个字节 最后两个字节
targets.push(chunk.slice(0, 2))
targets.push(chunk.slice(CHUNK_SIZE / 2, CHUNK_SIZE / 2 + 2))
targets.push(chunk.slice(CHUNK_SIZE - 2, CHUNK_SIZE))
}
})
fileReader.readAsArrayBuffer(new Blob(targets))
fileReader.onload = (e) => {
spark.append(e.target.result)
//计算的hash值
// console.log('hash', spark.end())
resolve(spark.end())
}
})
}
/** 通知服务器 **/
const mergeRequest = () =>{
fetch('http://localhost:3000/merge',{
method: 'POST',
headers:{
'content-type': 'application/json'
},
body:JSON.stringify({
fileHash: fileHash.value,
fileName: fileName.value,
size:CHUNK_SIZE
})
}).then(res=>{
console.log("合并成功")
})
}
/** 上传文件 **/
const uploadChunks = async (chunks) => {
//构造数组
const data = chunks.map((chunk, index) => {
return {
fileHash: fileHash.value,
chunkHash: fileHash.value + '-' + index,
chunk: chunk
}
})
//构造上传需要的formdata
const formDatas = data.map((item) => {
const formData = new FormData()
formData.append('fileHash', item.fileHash)
formData.append('chunkHash', item.chunkHash)
formData.append('chunk', item.chunk)
return formData
})
let max = 6 //最大请求数
let index = 0
const taskPool = [] //请求池
while (index < formDatas.length) {
const task = fetch('http://localhost:3000/upload', {
method: 'POST',
body: formDatas[index]
})
taskPool.splice(taskPool.findIndex(item => item === task))
taskPool.push(task)
if (taskPool.length === max) {
await Promise.race(taskPool)
}
index++
}
await Promise.all(taskPool)
//通知服务器合并请求
mergeRequest()
}
/** 获取文件对象 **/
const handleUpload = async (e) => {
let files = e.target.files;
if (!files) return
fileName.value = files[0].name
//文件分片
const chunks = createChunks(files[0])
//hash计算
const hash = await calculateHash(chunks)
fileHash.value = hash
console.log(hash)
//上传分片
uploadChunks(chunks)
}
</script>
<style scoped>
</style>
本文链接:https://www.xlsir.cn/js/16.html