当这个文件数据量也不是很多的时候,有很多前端工具可供选择。例如 SheetJS,就提供了从 Excel、CSV 中解析出用信息的很多方法,
当数据量只是几千条的程度的,选择的余地很多,但是一旦数据量级增加,处理就变得复杂。如果 XLSX/CSV 数据量达到了 100w+ 条,Office、WPS 想打开看一下,都会需要很长的时间
从本地 Excel、CSV、TXT(或者其他格式的)文件中解析出数据,文件体积可能是 5M、50M、500M 甚至更大、
满足以下几项需求
- 大体积文件支持切片上传
- 可以断点续传
- 可以得知上传进度
大文件分片,需要了解Web 页面基本都是通过 <input type='file' /> 来获取本地文件的。 而通过 input 的 event.target.files 获取到的 file,其实是一个 File 类的实例,是 Blob 类的子类,Blob 对象表示一个不可变、原始数据的类文件对象,简单理解合一将 Blob 看做二进制容器,表示存放着一个大的二进制文件。Blob 对象有一个很重要的方法:slice(),这里需要注意的是 Blob 对象是不可变的,slice 方法返回的是一个新的 Blob,表示所需要切割的二进制文件。
slice() 方法接受三个参数,起始偏移量,结束偏移量,还有可选的 mime 类型。如果 mime 类型,没有设置,那么新的 Blob 对象的 mime 类型和父级一样。而 File 接口基于 Blob,File 对象也包含了slice方法,其结果包含有源 Blob 对象中指定范围的数据。
切割的方法,二进制文件进行拆分,
function sliceInPiece(file, piece = 1024 * 1024 * 5) {
let totalSize = file.size; // 文件总大小
let start = 0; // 每次上传的开始字节
let end = start + piece; // 每次上传的结尾字节
let chunks = []
while (start < totalSize) {
// 根据长度截取每次需要上传的数据
// File对象继承自Blob对象,因此包含slice方法
let blob = file.slice(start, end);
chunks.push(blob)
start = end;
end = start + piece;
}
return chunks
}
获得文件切割后的数组后,调用接口上传至服务端
let file = document.querySelector("[name=file]").files[0];
const LENGTH = 1024 * 1024 * 0.1;
let chunks = sliceInPiece(file, LENGTH); // 首先拆分切片
chunks.forEach(chunk=>{
let fd = new FormData();
fd.append("file", chunk);
post('/upload', fd)
})
上传完成后再至服务端将切片文件拼接成完整文件,让 FileReader 对象从 Blob 中读取数据,通过构造切片的 FormData 时增加参数的方式来处理。比如用参数 ChunkIndex 表示当前切片的顺序,
断点续传
在上传大文件或移动端上传文件时,因为网络质量、传输时间过长等原因造成上传失败,可以使用断点续传。特别地,断点续传上传的图片不支持预处理。特别地,断点续传上传的文件不能使用其他上传方式覆盖,如果需要覆盖,须先删除文件,
名称概念
- 文件分块:直接切分二进制文件成小块。分块大小固定为 1M。最后一个分块除外。
- 上传阶段:使用 x-upyun-multi-stage 参数来指示断点续传的阶段。分为以下三个阶段: initate(上传初始化), upload(上传中), complete(上传结束)。各阶段依次进行。
- 分片序号:使用 x-upyun-part-id 参数来指示当前的分片序号,序号从 0 起算。
- 顺序上传:对于同一个断点续传任务,只支持顺序上传。
- 上传标识:使用 x-upyun-multi-uuid 参数来唯一标识一次上传任务, 类型为字符串, 长度为 36 位。
- 上传清理:断点续传未完成的文件,会保存 24 小时,超过后,文件会被删除。