js分片下载超出2G的大文件代码实例
作者:SmallFatMan
为了实现断点续传,研究了js的文件分片,下面这篇文章主要给大家介绍了关于js分片下载超出2G的大文件的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
思路
针对超过2G的大文件,通常需要将文件进行分块下载,以避免浏览器的内存溢出或者因为网络连接不稳定而导致整个下载失败的情况。
下面是一个基本的分块下载的代码样例:
async downloadFile(url, fileName) {
const CHUNK_SIZE = 1024 * 1024 * 10 // 每次下载10MB
const response = await fetch(url)
const contentRange = response.headers.get('content-range')
const fileSize = contentRange ? Number(contentRange.split('/')[1]) : response.headers.get('content-length')
const fileStream = []
let offset = 0
while (offset < fileSize) {
const end = Math.min(offset + CHUNK_SIZE, fileSize)
const options = {
headers: { 'Range': `bytes=${offset}-${end - 1}` }
}
const blob = await fetch(url, options).then(res => res.blob())
fileStream.push(blob)
offset = end
}
const blob = new Blob(fileStream, { type: response.headers.get('content-type') })
saveAs(blob, fileName)
}
解释
这段代码使用了Fetch API来下载文件,同时使用了Range头来告诉服务器只需要下载文件的一部分。将文件大小分割为块,每次下载一块数据,最后将数据组合成一个Blob对象进行下载。需要注意的是,如果下载的文件有Content-Range头,则需要先从这个头里获取文件总大小。
async downloadFile(url, fileName) {
- 这段代码是一个异步函数,用于从给定的URL下载大文件,并使用blob对象保存文件。
- 该函数需要传入两个参数,一个是要下载的文件的url,另外一个则是下载后要保存的文件名。
const CHUNK_SIZE = 1024 * 1024 * 10 // 每次下载10MB
- 为了避免下载整个文件的时候因为内存不足而导致的错误,把文件划分成了多个大小相等的块,每次下载一个块的数据。这里设置每次下载的块为10MB。
const response = await fetch(url)
const contentRange = response.headers.get('content-range')
const fileSize = contentRange ? Number(contentRange.split('/')[1]) : response.headers.get('content-length')
- 使用Fetch API向服务器请求数据。从响应头里获取了Content-Range,这个头可以告诉服务器只需要下载文件的一部分。如果不存在Content-Range头,那么就通过response.headers.get(‘content-length’)获取文件的总大小。
const fileStream = []
let offset = 0
while (offset < fileSize) {
const end = Math.min(offset + CHUNK_SIZE, fileSize)
const options = {
headers: { 'Range': `bytes=${offset}-${end - 1}` }
}
const blob = await fetch(url, options).then(res => res.blob())
fileStream.push(blob)
offset = end
}
- 使用一个while循环将整个文件分块下载,每次下载一块数据。
- 循环中定义了两个变量:一个是fileStream,用于保存从服务器下载的每个块;另一个则是offset,表示已经下载的数据大小。
- 在每次循环开始时,首先计算本次下载的起点和终点,然后构造一个包含Range头的选项对象。将起点和终点放在Range头里,这样服务器就只会返回指定范围的数据。最后,使用Fetch API向服务器请求数据,并将用于保存数据的Blob对象推入fileStream数组中。
- 最后,更新offset的值,表示已经下载的总大小。
const blob = new Blob(fileStream, { type: response.headers.get('content-type') })
saveAs(blob, fileName)
- 在while循环结束后,将fileStream数组中的所有Blob对象合并为一个Blob对象,并使用FileSaver.js的saveAs函数来将其保存在本地磁盘上。
- 需要注意的是,在Blob的构造函数中传入了response.headers.get(‘content-type’),这是由于下载的文件类型不一定是常规的文件类型,所以我们需要从响应头中获取正确的文件类型。
- 以上就是该函数的所有内容,它通过将文件划分为多个块,避免了下载整个大文件时可能导致的内存溢出等问题,并且没有在浏览器中产生任何严重的内存或性能问题。
附:javascript 大文件下载,分片下载,断点续传
// 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();
总结
到此这篇关于js分片下载超出2G大文件的文章就介绍到这了,更多相关js分片下载超2G大文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
