js分片下载超出2G的大文件代码实例

 更新时间:2024年04月19日 10:39:06   作者: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大文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 前端Token 组成及生成方法示例详解

    前端Token 组成及生成方法示例详解

    这篇文章主要为大家介绍了前端Token 组成及生成方法示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-04-04
  • 小程序中手机号识别的示例

    小程序中手机号识别的示例

    这篇文章主要介绍了小程序中手机号识别的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • js模拟hashtable的简单实例

    js模拟hashtable的简单实例

    本篇文章主要是对js模拟hashtable的简单实例进行了介绍,需要的朋友可以过来参考下,希望对大家有所帮助
    2014-03-03
  • javascript检查某个元素在数组中的索引值

    javascript检查某个元素在数组中的索引值

    在js中提供数据查找了函数有很多,但我查找了很久都没有能实现我要的方法,后来发现可以使用indexOf函数来实现查找与定位数组元素索引值的具体方法,各位朋友可参考
    2016-03-03
  • Bootstrap选项卡动态切换效果

    Bootstrap选项卡动态切换效果

    这篇文章主要为大家详细介绍了Bootstrap选项卡动态切换效果,点击登录和注册可以实现任意切换,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-11-11
  • JavaScript6 let 新语法优势介绍

    JavaScript6 let 新语法优势介绍

    这篇文章主要介绍了JavaScript6 let 新语法优势介绍的相关资料,需要的朋友可以参考下
    2016-07-07
  • 一文详解JavaScript中的按值传递和按引用传递

    一文详解JavaScript中的按值传递和按引用传递

    编程语言中,把一个变量的值赋值给另一个变量,或者给函数调用传递参数有两种方式:按值传递和按引用传递,本文将给大家详细介绍JavaScript中的按值传递和按引用传递,需要的朋友可以参考下
    2024-05-05
  • JS实现头条新闻的经典轮播图效果示例

    JS实现头条新闻的经典轮播图效果示例

    这篇文章主要介绍了JS实现头条新闻的经典轮播图效果,涉及javascript图片轮播切换相关实现技巧,需要的朋友可以参考下
    2019-01-01
  • Echarts地图添加引导线效果(labelLine)

    Echarts地图添加引导线效果(labelLine)

    这篇文章主要介绍了Echarts地图添加引导线效果(labelLine),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • javascript 判断一个对象为数组的方法

    javascript 判断一个对象为数组的方法

    这篇文章主要介绍了javascript 判断一个对象为数组的方法的相关资料,需要的朋友可以参考下
    2017-05-05

最新评论