vue3+vite+typescript实现大文件前端部分
<script setup lang="ts">
import SparkMD5 from 'spark-md5';
// 文件分片大小
const CHUNK_SIZE = 1024 * 1024;
// 假设的服务器端点,替换为实际的URL
const SERVER_ENDPOINT = 'https://server-endpoint/upload';
// 文件分片
const createChunks = (file: File) => {
let cur = 0;
let chunks: Blob[] = [];
while (cur < file.size) {
const blob = file.slice(cur, cur + CHUNK_SIZE);
chunks.push(blob);
cur += CHUNK_SIZE;
}
return chunks;
};
// 计算文件hash值
const calculateHash = (chunks: Blob[]) => {
return new Promise((resolve, reject) => {
const targets: Blob[] = []; // 所有参与计算的切片
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 - 2, CHUNK_SIZE / 2 + 2)); // 中间两个字节
targets.push(chunk.slice(CHUNK_SIZE - 2)); // 最后两个字节
}
});
const readNext = () => {
if (targets.length === 0) {
resolve(spark.end(true));
return;
}
const target = targets.shift();
fileReader.readAsArrayBuffer(target);
};
fileReader.onload = () => {
const result = fileReader.result as ArrayBuffer;
spark.append(result);
readNext();
};
fileReader.onerror = (error) => {
reject(error);
};
readNext();
});
};
// 单个分片上传函数
const uploadChunk = (chunk: Blob, index: number, totalChunks: number) => {
const formData = new FormData();
formData.append('file', chunk, `chunk_${index}_of_${totalChunks}`);
formData.append('hash', ''); // 这里可以添加文件的总hash值,如果需要
return fetch(SERVER_ENDPOINT, {
method: 'POST',
body: formData,
}).then(response => {
if (!response.ok) {
throw new Error(`上传分片${index}失败`);
}
return response; // 这里可以根据服务器的响应来处理,例如返回上传成功的状态
});
};
// 文件上传
const handleLoad = async (e: Event) => {
const input = e.target as HTMLInputElement;
const files = input.files;
if (!files || files.length === 0) return;
const file = files[0];
console.log('文件:', file);
// 文件分片
const chunks = createChunks(file);
console.log('分片数量:', chunks.length);
// 计算文件hash值
const hash = await calculateHash(chunks);
console.log('文件Hash:', hash);
console.log('文件Hash:', hash);
try {
// 上传所有分片
const uploadPromises = chunks.map((chunk, index) => {
return uploadChunk(chunk, index, chunks.length);
});
const uploadResults = await Promise.all(uploadPromises);
console.log('所有分片上传完成:', uploadResults);
// 这里可以添加上传完成后的逻辑,例如通知用户上传成功
} catch (error) {
console.error('文件上传失败:', error);
}
};
</script>
<template>
<div>
<input type="file" @change="handleLoad" />
</div>
</template>
<style scoped>
</style>