文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

JavaScript怎么实现大文件分片上传处理

2023-06-20 18:45

关注

这篇文章主要介绍“JavaScript怎么实现大文件分片上传处理”,在日常操作中,相信很多人在JavaScript怎么实现大文件分片上传处理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript怎么实现大文件分片上传处理”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

很多时候我们在处理文件上传时,如视频文件,小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题:

文件过大,超出服务端的请求大小限制;
2、请求时间过长,请求超时;
3、传输中断,必须重新上传导致前功尽弃

这些问题很影响用户的体验感,所以下面介绍一种基于原生JavaScript进行文件分片处理上传的方案,具体实现过程如下:

通过dom获取文件对象,并且对文件进行MD5加密(文件内容+文件标题形式),采用SparkMD5进行文件加密;
2、进行分片设置,文件File基于Blob, 继承了Blob的功能,可以把File当成Blob的子类,利于Blob的slice方法进行文件分片处理,并且依次进行上传
3、分片文件上传完成后,请求合并接口后端进行文件合并处理即可

1. 上传文件页面

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <title>文件上传</title>  <script src="https://cdn.bootcss.com/axios/0.18.0/axios.min.js"></script>  <script src="https://code.jquery.com/jquery-3.4.1.js"></script>  <script src="https://cdnjs.cloudflare.com/ajax/libs/spark-md5/3.0.0/spark-md5.js"></script>  <style>        .precent input[type=range] {      -webkit-appearance: none;            width: 7.8rem;                  background-size: 75% 100%;            height: 0.6rem;            border-radius: 0.4rem;      border: 1px solid #ddd;      box-shadow: 0 0 10px rgba(0,0,0,.125) inset ;    }        .precent input[type=range]::-webkit-slider-thumb {      -webkit-appearance: none;            height: .9rem;            width: .9rem;            background: #fff;            border-radius: 50%;            border: solid 1px #ddd;          }  </style></head><body>  <h2>大文件分片上传测试</h2>  <div>    <input id="file" type="file" name="avatar" />    <div >      <input id="submitBtn" type="button" value="提交" />      <input id="pauseBtn" type="button" value="暂停" />    </div>    <div class="precent">      <input type="range" value="0" /><span id="precentVal">0%</span>    </div>  </div>  <script type="text/javascript" src="./js/index.js"></script></body></html>

大文件分片上传处理

$(document).ready(() => {  const submitBtn = $('#submitBtn');  //提交按钮  const precentDom = $(".precent input")[0]; // 进度条  const precentVal = $("#precentVal");  // 进度条值对应dom  const pauseBtn = $('#pauseBtn');  // 暂停按钮  // 每个chunk的大小,设置为1兆  const chunkSize = 1 * 1024 * 1024;  // 获取slice方法,做兼容处理  const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;  // 对文件进行MD5加密(文件内容+文件标题形式)  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();          // 通过内容和文件名称进行md5加密          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);    });  }  // 提交  submitBtn.on('click', async () => {    var pauseStatus = false;    var nowUploadNums = 0    // 1.读取文件    const fileDom = $('#file')[0];    const files = fileDom.files;    const file = files[0];    if (!file) {      alert('没有获取文件');      return;    }    // 2.设置分片参数属性、获取文件MD5值    const hash = await hashFile(file); //文件 hash     const blockCount = Math.ceil(file.size / chunkSize); // 分片总数    const axiosPromiseArray = []; // axiosPromise数组    // 文件上传    const uploadFile = () => {      const start = nowUploadNums * chunkSize;      const end = Math.min(file.size, start + chunkSize);      // 构建表单      const form = new FormData();      // blobSlice.call(file, start, end)方法是用于进行文件分片      form.append('file', blobSlice.call(file, start, end));      form.append('index', nowUploadNums);      form.append('hash', hash);      // ajax提交 分片,此时 content-type 为 multipart/form-data      const axiosOptions = {        onUploadProgress: e => {          nowUploadNums++;          // 判断分片是否上传完成          if (nowUploadNums < blockCount) {            setPrecent(nowUploadNums, blockCount);            uploadFile(nowUploadNums)          } else {            // 4.所有分片上传后,请求合并分片文件            axios.all(axiosPromiseArray).then(() => {              setPrecent(blockCount, blockCount); // 全部上传完成              axios.post('/file/merge_chunks', {                name: file.name,                total: blockCount,                hash              }).then(res => {                console.log(res.data, file);                pauseStatus = false;                alert('上传成功');              }).catch(err => {                console.log(err);              });            });          }        },      };      // 加入到 Promise 数组中      if (!pauseStatus) {        axiosPromiseArray.push(axios.post('/file/upload', form, axiosOptions));      }    }    // 设置进度条    function setPrecent(now, total) {      var prencentValue = ((now / total) * 100).toFixed(2)      precentDom.value = prencentValue      precentVal.text(prencentValue + '%')      precentDom.style.cssText = `background:-webkit-linear-gradient(top, #059CFA, #059CFA) 0% 0% / ${prencentValue}% 100% no-repeat`    }    // 暂停    pauseBtn.on('click', (e) => {      pauseStatus = !pauseStatus;      e.currentTarget.value = pauseStatus ? '开始' : '暂停'      if (!pauseStatus) {        uploadFile(nowUploadNums)      }    })    uploadFile();  });})

文件上传和合并分片文件接口(node)

const Router = require('koa-router');const multer = require('koa-multer');const fs = require('fs-extra');const path = require('path');const router = new Router();const { mkdirsSync } = require('../utils/dir');const uploadPath = path.join(__dirname, 'upload');const chunkUploadPath = path.join(uploadPath, 'temp');const upload = multer({ dest: chunkUploadPath });// 文件上传接口router.post('/file/upload', upload.single('file'), async (ctx, next) => {  const { index, hash } = ctx.req.body;  const chunksPath = path.join(chunkUploadPath, hash, '/');  if(!fs.existsSync(chunksPath)) mkdirsSync(chunksPath);  fs.renameSync(ctx.req.file.path, chunksPath + hash + '-' + index);  ctx.status = 200;  ctx.res.end('Success');}) // 合并分片文件接口router.post('/file/merge_chunks', async (ctx, next) => {  const { name, total, hash } = ctx.request.body;  const chunksPath = path.join(chunkUploadPath, hash, '/');  const filePath = path.join(uploadPath, name);  // 读取所有的chunks  const chunks = fs.readdirSync(chunksPath);  // 创建存储文件  fs.writeFileSync(filePath, '');   if(chunks.length !== total || chunks.length === 0) {    ctx.status = 200;    ctx.res.end('切片文件数量不符合');    return;  }  for (let i = 0; i < total; i++) {    // 追加写入到文件中    fs.appendFileSync(filePath, fs.readFileSync(chunksPath + hash + '-' +i));    // 删除本次使用的chunk        fs.unlinkSync(chunksPath + hash + '-' +i);  }  fs.rmdirSync(chunksPath);  // 文件合并成功,可以把文件信息进行入库。  ctx.status = 200;  ctx.res.end('Success');})

以上就是文件分片上传的基本过程,过程中加入了上传进度条、暂停和开始上传操作,见详细代码

到此,关于“JavaScript怎么实现大文件分片上传处理”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯