前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Electron文件分片上传

Electron文件分片上传

作者头像
码客说
发布2021-01-29 07:19:40
1.5K0
发布2021-01-29 07:19:40
举报
文章被收录于专栏:码客

获取文件分片

代码语言:javascript
复制
let stats = fs.statSync(filepath);//读取文件信息
let chunkSize = 3*1024*1024;//每片分块的大小3M
let size = stats.size;//文件大小
let pieces = Math.ceil(size / chunkSize);//总共的分片数  
function uploadPiece (i){ 
    //计算每块的结束位置
    let startdata = i * chunkSize;
    let enddata = Math.min(size, (i + 1) * chunkSize);
    let arr = [];
    //创建一个readStream对象,根据文件起始位置和结束位置读取固定的分片
    let readStream = fs.createReadStream(filepath,
                                         {start: startdata, end: enddata - 1}
                                        );
    //on data读取数据
    readStream.on('data', (data)=>{
        arr.push(data)
    }) 
    //on end在该分片读取完成时触发
    readStream.on('end', ()=>{
        //这里服务端只接受blob对象,需要把原始的数据流转成blob对象,这块为了配合后端才转
        let blob = new Blob(arr)
        //新建formdata数据对象
        var formdata = new FormData();
        let md5Val = md5(Buffer.concat(arr));
        formdata.append("file", blob);
        console.log('blob.size',blob.size)
        formdata.append("md5", md5Val);
        formdata.append("size", size + ''); // 数字30被转换成字符串"30"
        formdata.append("chunk", i + '');//第几个分片,从0开始
        formdata.append("chunks", pieces + '');//分片数
        formdata.append("name", name);//文件名
        post(formdata)//这里是伪代码,实现上传,开发者自己实现
    })
}

获取文件hash值

代码语言:javascript
复制
const hashFile = (file) => {
    return new Promise((resolve, reject) => {
        const chunks = Math.ceil(file.size / chunkSize);
        let currentChunk = 0;
        const spark = new SparkMD5.ArrayBuffer();
        const fileReader = new FileReader();

        function loadNext() {
            const start = currentChunk * chunkSize;
            const end = start + chunkSize >= file.size ? file.size : start + chunkSize;
            fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
        }

        fileReader.onload = e => {
            spark.append(e.target.result); // Append array buffer
            currentChunk += 1;
            if (currentChunk < chunks) {
                loadNext();
            } else {
                console.log('finished loading');
                const result = spark.end();
                // 如果单纯的使用result 作为hash值的时候, 如果文件内容相同,而名称不同的时候
                // 想保留两个文件无法保留。所以把文件名称加上。
                const sparkMd5 = new SparkMD5();
                sparkMd5.append(result);
                sparkMd5.append(file.name);
                const hexHash = sparkMd5.end();
                resolve(hexHash);
            }
        };
        fileReader.onerror = () => {
            console.warn('文件读取失败!');
        };
        loadNext();
    }).catch(err => {
        console.log(err);
    });
}

分片上传文件

代码语言:javascript
复制
const chunkSize = 2 * 1024 * 1024; // 每个chunk的大小,设置为2兆
// 使用Blob.slice方法来对文件进行分割。
// 同时该方法在不同的浏览器使用方式不同。
const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;

let file = new File();
if (!file) {
    alert('没有获取文件');
    return;
}
const blockCount = Math.ceil(file.size / chunkSize); // 分片总数
const axiosPromiseArray = []; // axiosPromise数组
const hash = await hashFile(file); //文件 hash
// 获取文件hash之后,如果需要做断点续传,可以根据hash值去后台进行校验。
// 看看是否已经上传过该文件,并且是否已经传送完成以及已经上传的切片。
console.log(hash);

for (let i = 0; i < blockCount; i++) {
    const start = i * chunkSize;
    const end = Math.min(file.size, start + chunkSize);
    // 构建表单
    const form = new FormData();
    form.append('file', blobSlice.call(file, start, end));
    form.append('identifier', file.name);
    form.append('filename', file.name);
    form.append('chunkNumber', i+1);
    form.append('size', file.size);
    form.append('hash', hash);
    // ajax提交 分片,此时 content-type 为 multipart/form-data
    const axiosOptions = {
        onUploadProgress: e => {
            // 处理上传的进度
            console.log(blockCount, i, e, file);
        },
    };
    // 加入到 Promise 数组中
    axiosPromiseArray.push(axios.post('/file/upload', form, axiosOptions));
}
// 所有分片上传后,请求合并分片文件
await axios.all(axiosPromiseArray).then(() => {
    // 合并chunks
    const data = {
        size: file.size,
        name: file.name,
        total: blockCount,
        hash
    };
    axios.post('/file/merge_chunks', data).then(res => {
        console.log('上传成功');
        console.log(res.data, file);
        alert('上传成功');
    }).catch(err => {
        console.log(err);
    });
});

Node上传文件

代码语言:javascript
复制
async uploadfile() {
    let that = this;
    let filepath = this.filepath;
    let filename = filepath.split("/").reverse()[0];
    let stats = fs.statSync(filepath);//读取文件信息
    let chunkSize = 3 * 1024 * 1024;//每片分块的大小3M
    let size = stats.size;//文件大小
    let piecesAll = Math.ceil(size / chunkSize);//总共的分片数
    let identifier = parseInt(new Date().getTime() / 1000 + "");
    let savefolder = this.userInfo.schoolid + "/live";
    const axiosPromiseArray = []; // axiosPromise数组
    console.info("文件大小:" + size);
    console.info("文件分片:" + piecesAll);
    console.info("identifier", identifier)
    console.info("filename", filename)
    console.info("savefolder", this.userInfo.schoolid + "/live")
    let readPieces = 0;//已读取的文件片数
    for (let i = 0; i < piecesAll; i++) {
        let startdata = i * chunkSize;
        let enddata = Math.min(size, (i + 1) * chunkSize);
        let arr = [];
        //创建一个readStream对象,根据文件起始位置和结束位置读取固定的分片
        let readStream = fs.createReadStream(filepath,
                                             {start: startdata, end: enddata - 1}
                                            );
        //on data读取数据
        readStream.on('data', (data) => {
            arr.push(data)
        })

        //on end在该分片读取完成时触发
        readStream.on('end', () => {
            //这里服务端只接受blob对象,需要把原始的数据流转成blob对象,这块为了配合后端才转
            let blob = new Blob(arr)
            //新建formdata数据对象
            const form = new FormData();
            form.append('file', blob);
            form.append('identifier', identifier);
            form.append('filename', filename);
            form.append('chunkNumber', i + 1);
            form.append('savefolder', savefolder);
            //加入到 Promise 数组中
            axiosPromiseArray.push(axios.post(fileuploadUrl + 'chunk/up', form, {
                headers:
                {'Content-Type': 'application/x-www-form-urlencoded'}
            }));

            readPieces += 1;
            that.tipmsg.progress = parseInt((readPieces * 100 / piecesAll) + "")
            if (readPieces === piecesAll) {
                axios.all(axiosPromiseArray).then(() => {
                    // 合并chunks
                    const form = new FormData();
                    form.append('savefolder', savefolder);
                    form.append('identifier', identifier + "");
                    form.append('filename', filename);
                    form.append('thumed', 1 + "");
                    form.append('rename', 1 + "");
                    axios.post(fileuploadUrl + 'chunk/mergevideo', form, {
                        headers: {
                            'Content-Type': 'application/x-www-form-urlencoded'
                        }
                    }
                              ).then(res => {
                        console.log('上传成功');
                        console.log("res.data", res.data);
                        axios.post(apiUrl + "section/update_playback", {
                            sectionid: that.sectionid,
                            mp4code: res.data.obj.mp4code || "h264",
                            playback: res.data.obj.videopath
                        }).then(res3 => {
                            win.close()
                        }).catch(err3 => {
                            win.close()
                        })
                        // win.close()
                    }).catch(err => {
                        console.log(err);
                        win.close()
                    });
                });
            }
        })
    }
}

关键点

记录已经读取的分片数量 当所有分片都已经读取后再调用合并接口

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-01-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取文件分片
  • 获取文件hash值
  • 分片上传文件
  • Node上传文件
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档