javascript 大文件下载,分片下载,断点续传
既然是断点续传,自然离不开分片下载。接下来,我们将一个文件分片并一个一个下载。首先,我们需要获取文件的大小,以便更好地对其进行分段。
·
javascript 大文件下载,分片下载,断点续传
既然是断点续传,自然离不开分片下载。接下来,我们将一个文件分片并一个一个下载。
首先,我们需要获取文件的大小,以便更好地对其进行分段。
1:获取文件大小:
// status
const DONE = 4;
// get content length
function getContentLength(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', url, true);
xhr.onreadystatechange = function () {
if (this.readyState == DONE) {
resolve(this.getResponseHeader('Content-Length'));
}
}
xhr.send();
})
}
得到文件大小后,对其进行切片,得到对应切片的内容。
因为这里的测试文件不是很大,所以每个切片的大小设置为100。
具体大小视个人需求而定。
2:切片下载
// status
const DONE = 4;
// range size
const RANGE_SIZE = 100;
// get range content
function getRangeContent(startIndex, endIndex, url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Range', `bytes=${startIndex}-${endIndex}`);
xhr.responseType = 'arraybuffer';
xhr.onreadystatechange = function () {
if (this.readyState == DONE) {
resolve(this.response);
}
}
xhr.send();
})
}
因为是arraybuffer类型的内容,这里我们使用Uint8Array视图来接受合并。
3:合并数据
// concat arraybuffer array
function concatArrayBuffer(arrayBufferArray) {
let totalLength = 0;
arrayBufferArray.forEach(arrayBuffer => {
totalLength += arrayBuffer.byteLength;
});
const result = new Uint8Array(totalLength);
let offset = 0;
arrayBufferArray.forEach(arrayBuffer => {
result.set(new Uint8Array(arrayBuffer), offset);
offset += arrayBuffer.byteLength;
});
return result;
}
如果您有下载的需要,这里有一个示例,您可以将合并后的数据下载到本地。
4:下载到本地
// download arraybuffer file
function downloadArrayBufferFile(arrayBuffer, fileName) {
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileName;
a.click();
}
然后你就可以得到完整的内容了。
5:成功
// main methoeds
async function main() {
const fileUrl = 'http://localhost:8083/public/m2.jpeg';
const contentLength = await getContentLength(fileUrl);
const numberRequest = Math.ceil(contentLength / RANGE_SIZE);
const arrayBufferArray = [];
for (let i = 0; i < numberRequest; i++) {
const startIndex = i * RANGE_SIZE;
const endIndex = startIndex + RANGE_SIZE - 1;
const clip = await getRangeContent(startIndex, endIndex, fileUrl);
arrayBufferArray.push(clip);
}
const result = concatArrayBuffer(arrayBufferArray);
downloadArrayBufferFile(result, 'access.txt');
}
6:完整代码
// status
const DONE = 4;
// range size
const RANGE_SIZE = 100;
// get content length
function getContentLength(url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', url, true);
xhr.onreadystatechange = function () {
if (this.readyState == DONE) {
resolve(this.getResponseHeader('Content-Length'));
}
}
xhr.send();
})
}
// get range content
function getRangeContent(startIndex, endIndex, url) {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.setRequestHeader('Range', `bytes=${startIndex}-${endIndex}`);
xhr.responseType = 'arraybuffer';
xhr.onreadystatechange = function () {
if (this.readyState == DONE) {
console.log(this.response)
resolve(this.response);
}
}
xhr.send();
})
}
// download arraybuffer file
function downloadArrayBufferFile(arrayBuffer, fileName) {
const blob = new Blob([arrayBuffer], { type: 'application/octet-stream' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = fileName;
a.click();
}
// concat arraybuffer array
function concatArrayBuffer(arrayBufferArray) {
let totalLength = 0;
arrayBufferArray.forEach(arrayBuffer => {
totalLength += arrayBuffer.byteLength;
});
const result = new Uint8Array(totalLength);
let offset = 0;
arrayBufferArray.forEach(arrayBuffer => {
result.set(new Uint8Array(arrayBuffer), offset);
offset += arrayBuffer.byteLength;
});
return result;
}
// main methoeds
async function main() {
const fileUrl = 'http://localhost:8083/public/access.txt';
const contentLength = await getContentLength(fileUrl);
const numberRequest = Math.ceil(contentLength / RANGE_SIZE);
const arrayBufferArray = [];
for (let i = 0; i < numberRequest; i++) {
const startIndex = i * RANGE_SIZE;
const endIndex = startIndex + RANGE_SIZE - 1;
const clip = await getRangeContent(startIndex, endIndex, fileUrl);
arrayBufferArray.push(clip);
}
const result = concatArrayBuffer(arrayBufferArray);
downloadArrayBufferFile(result, 'access.txt');
}
main();
至此,你应该有断点续传的想法了。
只需要对已经分片的数据进行标记,最后将标记好的分片数据进行合并,就可以得到一个完整的文件。
即使途中网络中断,只要正确标记了段数据,没有获取到哪个段数据,就可以从服务器重新获取丢失的段数据到本地,合并完整的内容并再次下载。
如果还是不知道怎么做,可以给我留言,接下来我会介绍前后端配合标记验证数据。
更多推荐
已为社区贡献6条内容
所有评论(0)