JS分片下载大文件代码实例
作者:代码拾荒时间:2026-10-31 13:12:23浏览:361
本文介绍如何使用JavaScript和Fetch API实现大文件分片下载,通过Range请求头分段获取数据,有效避免浏览器内存溢出。示例代码演示了如何计算分块大小、循环下载并合并Blob对象,适用于处理超过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'),因为下载的文件类型可能非常规文件,需从响应头获取正确的MIME类型。
- 以上为该函数的完整内容。通过将文件划分为多个块,避免了下载整个大文件时可能导致的内存溢出等问题,且未在浏览器中产生严重的内存或性能问题。
附: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大文件内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!
作者最新文章
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
