这个问题对于一些视频网站,是非常常见的一个问题。
首先我们要知道为什么要分片上传。
- 提高上传速度:通过将大文件切割成多个小片段,可以减少单个文件的传输时间,从而提高上传速度。
- 提高上传稳定性:分片上传可以实现断点续传,即使在上传过程中断开连接,也可以从上次中断的地方继续上传,提高了上传的稳定性。
- 减少服务器压力:分片上传可以将大文件切割成多个小片段进行上传,这样可以减少服务器的压力,提高服务器的并发处理能力。
- 增加传输安全性:在某些情况下,对大文件进行分片上传可以增加数据的安全性,防止单个文件被攻击或篡改。
最简单的一个道理,我们拿b站的举例。如果我们再这个过程中,断网了。那么一整个文件是全部都要重新上传吗?很明显b站的做法不是的。
并且我们可以发现在上传的过程中

是不断的去发送ajax请求的。也就是我们要聊的分片上传
我们可以把一个大的文件,切成很多小片,一片一片的进行上传。
下面我们来看如何进行具体的实现。
如何进行分片
首先我们来进行一个实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <body> <input type="file" />
</body> <script> const input = document.querySelector('input'); input.onchange = (e)=>{ const file = input.files[0]; if (!file){ return; } console.log(file) } </script>
|
可以看到是一个File对象

之后我们用这个要用到slice
函数
1 2
| const blob = file.slice(0,100); console.log(blob)
|
这个打印出来的东西可以自己去看 Blob对象没有特定的数据类型,只是原始数据的一个包装
知道这个原理之后。我们以此来封装一个函数
1 2 3 4 5 6 7
| function createChunks(file,chunkSize){ const result=[] for (let i = 0; i < file.size; i+=chunkSize){ result.push(file.slice(i,i+chunkSize)) } return result; }
|
1 2
| const chunks = createChunks(file,10*1024*1024); console.log(chunks)
|
可以看到这就完成的切片操作

Blob对象有两个主要属性:
size
:Blob的字节长度。
type
:Blob的MIME类型,如果未知则返回空字符串。
之后我们需要读取数据的时候。需要FileReader才可以进行读取
关于如何把分片的内容合在一块,这就是后端要去做的了,我们前端的职责就是负责把请求通过ajax发送过去就可以了。
断网情况解决
为了解决断网后的情况,我们需要通过ajax不断的去告诉服务器,我们上传到了哪里。那么如何对文件进行唯一标识呢?
这里我们用到了spark-md5
安装:
1
| npm install --save spark-md5
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function hash(chunks) { return new Promise((resolve)=>{ const sparkMD5 = new SparkMD5(); function _read(i){ if (i>=chunks.length){ resolve(sparkMD5.end()) return; } const blob=chunks[i]; const fileReader = new FileReader(); fileReader.onload = e=> { const bytes = e.target.result; sparkMD5.append(bytes) _read(i+1) } fileReader.readAsArrayBuffer(blob) } _read(0) })
}
|
1
| const result = await hash(chunks)
|
这样就可以得到一个唯一的文件标识了。
下面就是上面用到的所有实例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title>
</head> <body> <input type="file" />
</body> <script src="spark-md5.js"></script> <script>
const input = document.querySelector('input'); input.onchange = async (e)=>{ const file = input.files[0]; if (!file){ return; } const chunks = createChunks(file,10*1024*1024); const result = await hash(chunks) console.log(result) }
function hash(chunks) { return new Promise((resolve)=>{ const sparkMD5 = new SparkMD5(); function _read(i){ if (i>=chunks.length){ resolve(sparkMD5.end()) return; } const blob=chunks[i]; const fileReader = new FileReader(); fileReader.onload = e=> { const bytes = e.target.result; sparkMD5.append(bytes) _read(i+1) } fileReader.readAsArrayBuffer(blob) } _read(0) })
}
function createChunks(file,chunkSize){ const result=[] for (let i = 0; i < file.size; i+=chunkSize){ result.push(file.slice(i,i+chunkSize)) } return result; } </script> </html>
|