Skip to main content

大文件离线分片上传

何为大文件分片上传

大文件分片上传是一种处理大文件上传的策略。它通过将一个大文件分割成若干个较小的数据片段(通常称为“分片”或“片段”),然后逐一上传这些片段。上传完成后,服务器将这些片段重新组合成原始的文件

为什么要使用大文件分片上传

断点续传:若文件在上传过程中出现了问题,如网络波动和连接中断,分片上传可以记录已成功上传的分片。这样,在恢复网络连接后,可以从中断点开始继续上传,而不是重新上传整个文件。这可以节省时间及带宽。大文件上传变得越来越重要,尤其是随着网络应用、多媒体和大规模数据处理需求的增长 这种方法可以带来许多好处,有利于大文件的上传和传输处理。以下是进行大文件分片上传的一些原因:

  • 上传速度加快:将文件拆分成多个分片并行上传,可以最大限度地利用带宽资源,从而提高上传速度。这对于大文件上传至关重要,特别是在网络环境较差的情况下。

  • 降低服务器资源和内存消耗:将大文件分为较小的片段可以降低服务器内存消耗,因为服务器一次只需处理较小的数据片段。这有助于提高服务器性能,特别是在同时处理多个上传进程时。

  • 避免单个文件大小限制:许多存储和服务提供商对单个上传文件的大小设置有限制。分片上传可以避免这种限制,因为每个数据片段的大小都小于限制。

  • 提高上传的可靠性:通过分片上传,可以在客户端对文件进行校验和验证。这有助于确保上传的文件完整且未被篡改。在每个片段上传完成后,可以对其进行校验,保证上传过程的可靠性和安全性。

前端如何上传大文件

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.5.0/axios.min.js" integrity="sha512-aoTNnqZcT8B4AmeCFmiSnDlc4Nj/KPaZyB5G7JnOnUEkdNpCZs1LCankiYi01sLTyWy+m2P+W4XM+BuQ3Q4/Dg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.2/spark-md5.min.js"
integrity="sha512-iWbxiCA4l1WTD0rRctt/BfDEmDC5PiVqFc6c1Rhj/GKjuj6tqrjrikTw3Sypm/eEgMa7jSOS9ydmDlOtxJKlSQ=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<title>Document</title>
</head>

<body>
<input id="file" type="file">
<script type="module" src="./js/index.js"></script>
</body>

</html>
import request from "./request.js";

const els = {
oFile: document.getElementById('file')
}
els.oFile.onchange = async (e) => {
const file = els.oFile.files[0];
if (!file) {
return
}
const chunkSize = 1024
const chunks = createChunk(file, chunkSize);
const hash = await createHash(chunks);

chunks.forEach((chunk, index) => {
const formData = new FormData();
formData.append('file', chunk, file.name);
formData.append('hash', hash);
request.post('upload', formData, {
headers: {
"Content-Range": encodeURIComponent(`bytes ${index * chunkSize}-${(index+1) * chunkSize - 1}/${file.size}`),
"Content-Disposition": encodeURIComponent(`attachment; filename="${file.name}"`),
"X-Slice-Index": encodeURIComponent(index),
"X-Total-Slices": encodeURIComponent(chunks.length),
"X-File-Hash": encodeURIComponent(hash),
}
})
})

console.log(hash);

}

const createChunk = (file, chunkSize) => {
const result = [];
for (let i = 0; i < file.size; i += chunkSize) {
result.push(file.slice(i, i + chunkSize))
}
return result
}

const createHash = (chunks) => new Promise((resolve) => {
const spark = new SparkMD5();
function _read(i) {
if (i >= chunks.length) {
resolve(spark.end())
return
}
const reader = new FileReader();
reader.onload = (e) => {
const tytes = e.target.result;
spark.append(tytes);
_read(i + 1)
}
const blob = chunks[i];
window.r = reader;
window.b = blob;

reader.readAsArrayBuffer(blob);
}
_read(0)
})