javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > js分片下载超2G大文件

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) {
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)

附: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大文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文