某站进行大文件上传时查看网络我们会发现会不断生成ajax请求这是由于:文件一旦过大,一次发送,时间将会很长,如果发送过程发生错误,我们很难承受后果。所以我们上传大文件的时候,往往会切片处理
1、对文件进行切片
file和blob只是保存数据的 size \ type \ name 这些数据
所以切片上传的是数组运算,所以很快,想要读到数据,使用fileReader
2、如果我们上传了一部分的时候,发生了断网需要重新传输,这时就需要断点续传
通过一次ajax请求,客户端从服务器获取到这个文件还需要传递哪些分片,那么“这个文件”如何描述呢?
能够唯一表示文件切片的----hash(md5) --------- hash将任何数据 ->固定长度字符串
现在我们来实现一下文件数据与hash的转化,当然这里不推荐使用一次性将所有数据转换成hash,我们采用切片、增量算法实现转化,这里我们定义一个方法接收数据块,并且引入三方库spark-md5实现hash转化
<!DOCTYPE html>
<html>
<head>
<title>大文件分片上传Demo</title>
<!-- 引入MD5计算库 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.2/spark-md5.min.js"></script>
</head>
<body>
<input type="file" id="fileInput" />
<script>
/* 1. 监听文件选择事件 */
document.querySelector('input').onchange = async function(e) {
const file = e.target.files[0];
if (!file) return;
/* 2. 文件切片处理 */
const chunks = sliceFile(file, 10 * 1024); // 每片10KB,根据网络来定
/* 3. 计算文件唯一hash*/
const fileHash = await computeHash(chunks); //异步执行
console.log('最终文件hash:', fileHash);
};
/* 文件切片函数 */
function sliceFile(file, chunkSize) {
const chunks = [];
// 用slice方法切割文件
for (let i = 0; i < file.size; i += chunkSize) {
chunks.push(file.slice(i, i + chunkSize));
}
return chunks;
}
/* 增量计算文件hash */
function computeHash(chunks) {
return new Promise(resolve => {
const spark = new SparkMD5(); // 创建MD5计算器
let processed = 0; // 已处理分片计数
function processChunk(index) {
// 所有分片处理完成
if (index >= chunks.length) {
resolve(spark.end()); // 返回最终hash
return;
}
const reader = new FileReader();
// 分片读取完成时
reader.onload = e => {
spark.append(e.target.result); // 增量更新hash
processed++;
processChunk(processed); // 处理下一分片
};
// 读取当前分片
reader.readAsArrayBuffer(chunks[index]);
}
processChunk(0); // 从第一个分片开始
});
}
</script>
</body>
</html>
也是实现了将文件切片转换成hash值,后续将hash值传给后端geigei处理吧
那么后续我们也可以直接根据后端返回的hash存储与文件数据的对应关系找到对应的文件哩:
文件存储流程:
文件检索流程: