• 大文件分块上传实现


    效果展示

     

    原理说明

    对于大文件上传这个问题,作为一个有追求的程序员一定会有所思考,解决这个问题无非就是将文件变小,也就是通过对文件压缩或者对大文件分块后再上传。下面我们就来看看将文件资源分块的方案

    代码实现之前端代码

    (1)创建一个vue项目

     

    (2)写一个简单页面

    (3)获取上传文件

    async  getFile(e) {      

      // 1.获取文件      

      let file = e.target.files;      

      this.currFile = file[0];

    },

    (4)大文件分块

    1. // 获取文件分块
    2.     getFileChunk(file, chunkSize) {
    3.       let that = this;
    4.       return new Promise((resovle) => {
    5.         let blobSlice =
    6.             File.prototype.slice ||
    7.             File.prototype.mozSlice ||
    8.             File.prototype.webkitSlice,
    9.           chunks = Math.ceil(file.size / chunkSize),
    10.           currentChunk = 0,
    11.           spark = new SparkMD5.ArrayBuffer(),
    12.           fileReader = new FileReader();
    13.        
    14.         //使用fileReader将文件块转为文件流,方便生成文件hash值
    15.         //这里生成文件hash的作用
    16.         fileReader.onload = function (e) {
    17.           const chunk = e.target.result;
    18.           spark.append(chunk);
    19.           currentChunk++;
    20.           if (currentChunk < chunks) {
    21.             loadNext();
    22.           } else {
    23.             let fileHash = spark.end();
    24.             resovle({ fileHash });
    25.           }
    26.         };
    27.         fileReader.onerror = function () {
    28.           console.warn("oops, something went wrong.");
    29.         };
    30.         function loadNext() {
    31.           //文件切块
    32.           let start = currentChunk * chunkSize,
    33.           end =start + chunkSize >= file.size ? file.size : start + chunkSize;
    34.           let chunk = blobSlice.call(file, start, end);
    35.           that.fileChunkList.push({
    36.             chunk,
    37.             size: chunk.size,
    38.             name: that.currFile.name,
    39.             percentage:0
    40.           });
    41.           fileReader.readAsArrayBuffer(chunk);
    42.         }
    43.         loadNext();
    44.       });
    45.     },

    (5)上传分块和合并请求

    1. // 上传请求
    2.     uploadChunks(fileHash) {
    3.       let that = this;
    4.       const requests = this.fileChunkList.map((item, index) => {
    5.         const formData = new FormData();
    6.         formData.append(
    7.           `${this.currFile.name}-${fileHash}-${index}`,
    8.           item.chunk
    9.         );
    10.         // 上传
    11.         return uploadFile("/upload", formData, that.onUploadProgress(item));
    12.       });
    13.       Promise.all(requests).then(() => {
    14.         // 合并
    15.         mergeChunks("/mergeChunks", {
    16.           size: that.DefualtChunkSize,
    17.           filename: that.currFile.name,
    18.         });
    19.       });
    20.     },
    21.      
    22.      
    23.      
    24. import axios from "axios";
    25. const baseURL = 'http://localhost:3001';
    26. export const uploadFile = (url, formData, onUploadProgress = () => { }) => { 
    27.     return axios({ 
    28.     method: 'post'
    29.     url, 
    30.     baseURL,  
    31.     headers: {  
    32.       'Content-Type': 'multipart/form-data'  
    33.     }, 
    34.     data: formData,  
    35.     onUploadProgress
    36.   });
    37. }
    38. export const mergeChunks = (url, data) => {
    39.   return axios({ 
    40.     method: 'post'
    41.     url,   
    42.     baseURL,  
    43.     headers: {
    44.       'Content-Type': 'application/json' 
    45.     }, 
    46.     data
    47.   });
    48. }

    代码实现之后端代码

    (1)初始化node.js项目,提供上传接口和合并接口

    1. npm install -g koa-generator   
    2. koa2 项目名
    3. npm install
    4. router.post("/upload", async (ctx) => { 
    5.                   ctx.set("Content-Type", "application/json"); 
    6.                   ctx.body = JSON.stringify({    data: {      code: 2000,    },    message: "successful!",  });
    7. });
    8. router.post("/mergeChunk", async (ctx) => { 
    9.            ctx.set("Content-Type", "application/json"); 
    10.            ctx.body = JSON.stringify({    data: {      code: 2000,    },    message: "successful!",  });
    11. });

    可能有跨域:需要配置一下

    const cors = require('koa2-cors');

     

    (2)使用koa-body处理文件分块

    const koaBody = require("koa-body")

     

    (3)处理合并请求

    1. // 合并请求
    2. router.post("/mergeChunks", async (ctx) => {
    3.   const { filename, size } = ctx.request.body;
    4.   // 合并 chunks
    5.   await mergeFileChunk(filename, size);
    6.   // 处理响应
    7.   ctx.set("Content-Type", "application/json");
    8.   ctx.body = JSON.stringify({
    9.     data: {
    10.       code: 2000,
    11.       filename,
    12.       size,
    13.     },
    14.     message: "merge chunks successful!",
    15.   });
    16. });

     

    (4)优化文件小块的进度条

     注意:这里在切块的时候,需要给每一块加上percentage字段,这样才能响应化!!!

  • 相关阅读:
    QT软件开发-基于FFMPEG设计视频播放器-支持流媒体地址播放(五)
    【藏经阁一起读】(72)__《Hologres 一站式实时数仓客户案例集》
    基于混合VNS(变邻域搜索算法)的PSO(粒子群优化算法)的任务分配问题(Matlab代码实现)
    洛谷基础题练习3
    注册域名,购买阿里云服务器,备案,域名解析图文教程简介
    用于提高开关电容器电路良率的基于公共质心的单元电容器的最佳布局
    tkinter上传文件
    定时执行专家 - 程序设计及源代码结构 by BoomWorks
    “1688商品评论接口:打造完美电商口碑的秘密武器!“
    个人电脑好用必备软件(使用过)
  • 原文地址:https://blog.csdn.net/qq_35577655/article/details/126881494