FileReader读取大文件

前端采用FileReader可以读取文件内容,但是在读取大文件,比如1-3GB文件时发现会有显著卡顿。这里Mark下优化办法。

https://static.1991421.cn/2024/2024-03-31-224554.jpeg

卡顿原因

全量读取文件的话,文件内容会都存入浏览器内存中,因此会出现卡顿。

解决办法

文件file进行slice分片,每次异步读取分片数据。

1
2
3
4
5
6
7
8
9
10
11
const chunkSize = 1 * 1024 * 1024; // 1MB
function readChunk(file, start, chunkSize) {
const reader = new FileReader();
return new Promise(resolve => {
reader.onload = (evt) => {
// console.log(evt.target.result);
resolve(evt.target.result);
};
reader.readAsArrayBuffer(file.slice(start, Math.min(start + chunkSize, file.size)));
})
}

对比

以2.3GB数据为例

  1. 使用FileReader.readAsArrayBuffer分1MB片读取数据,时间开销如下

    https://static.1991421.cn/2024/2024-03-31-223746.jpeg

  2. 使用FileReader.readAsArrayBuffer全量读取文件,发现一直没有读取结束

以1.98GB数据为例

  1. 分片读取

https://static.1991421.cn/2024/2024-03-31-223823.jpeg

  1. 全量读取

https://static.1991421.cn/2024/2024-03-31-223906.jpeg

结论

  1. 由上可以看到,分片读取文件内容是节约性能的,且更快能够读取到指定部分内容,但读取总时间并不一定比全量少。但文件越大,差距会越大。
  2. 2GB以上文件浏览器一次性全量读取会有问题。

延伸

在前端处理文件二进制是经常会遇到Blob和ArrayBuffer,如果只是单纯分片数据推荐Blob,blob只是原数据视图本身并没有打开销,因此比如上传文件,可以直接file.slice进行分片发送服务端即可。但如果需要前端读取文件内功,或者还要修改文件,则推荐ArrayBuffer。