前端大文件上传及切片上传-提升上传效率

news2024/10/6 18:28:41

 

一、使用场景:

1.大文件上传

2.网络环境环境不好,存在需要重传风险的场景

二、名词解释:

切片上传:也叫分片上传,就是将所要上传的文件,按照一定的大小,将整个文件分隔成多个数据块来进行分别上传,上传完之后再由服务端对所有上传的文件进行汇总整合成原始的文件。

断点续传:是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传或者下载未完成的部分,而没有必要从头开始上传或者下载。

三、实现流程步骤:

我们先来个简单的文件上传案例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>文件上传</title>
    <style>
      html,
      body {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
      }
    </style>
  </head>

  <body>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.js"></script>
    <input type="file" name="file" id="ipt" />
    <input type="button" οnclick="getData()" value="get请求数据"/>
    <button οnclick="upload()" type="button"> 上传</button>
    <script>
      function getData(){
        axios.get("http://localhost:9528/uname?name=abc").then((res) => {
          console.log(res.data);
        });
      }
      function upload() {
        const file = ipt.files[0];
        const formData = new FormData();
        formData.append("formData", file, file.name);
        console.log(formData);
        axios.post("http://localhost:9528/upload", formData).then((res) => {
          console.log(formData, res);
        });
      }
    </script>
  </body>
</html>

node服务端

const multiparty = require("multiparty");
const bodyParser = require("body-parser");
const path = require("path");
const express = require("express");
const app = express();
const cors = require('cors')
const fs = require("fs");
function resolvePath(dir) {
  return path.join(__dirname, dir);
}

app.use(cors())
app.use(express.static(resolvePath("/public")));
app.use(bodyParser.json({ limit: "50mb" }));
app.use(bodyParser.urlencoded({ extended: true }));

app.post("/upload", function (req, res) {
  const form = new multiparty.Form({ uploadDir: "public" });
  form.parse(req);
  form.on("file", function (name, file) {
    console.log(name, file);
    const { path, originalFilename } = file;
    fs.renameSync(path, `public/${originalFilename}`);
    res.json({
      url: `http://localhost:9528/${originalFilename}`,
      message: "发送成功",
    });
  });
});
app.get('/uname',function(req,res){
  console.log(req.query,req.params);
  // res.json({a:1,b:2})
   res.send({ name: "yang", age: 18 });
})

app.use(function (err, req, res, next) {
  console.log('server错误',err);
  res.send({
    err:err,
    message: "server错误"
  })
})

const port = 9528;
app.listen(port, function () {
  console.log(`listen port ${port}`);
});

测试上传:

可以看到这里已经上传成功,payload是一个二进制文件。服务端指定目录下就多了一个文件

一个简单的文件上传就完成了,现在开始切片上传功能开发,切片上传就是把一个文件切分成很多小文件,本来上传一个大文件,现在改成上传很多小文件

分片上传:

我们知道使用 <input type="file" name="file" /> 元素选择一个文件之后,会得到 File 对象,而 File 对象 又继承 Blob,正好 Blob 对象有个方法叫 slice。这个方法和数组的 slice 方法使用基本相同,它可以获取待上传文件的某一部分,经过 slice 方法处理之后得到的结果也是一个 Blob。

思路:

1、将需要上传的文件按照一定的分割规则,分割成相同大小的数据块;

2、初始化一个分片上传任务,返回本次分片上传唯一标识;

3、按照一定的策略(串行或并行)发送各个分片数据块;

4、发送完成后,服务端根据判断数据上传是否完整,如果完整,则进行数据块合成得到原始文件。

前端代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>分片上传</title>
    <style>
      html,
      body {
        display: flex;
        align-items: center;
        justify-content: center;
        height: 100%;
      }
    </style>
  </head>

  <body>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.js"></script>
    <script src="https://xiaojinhe-cdn.iyoudui.cn/upload/common/2022129/spark-md5.min.js"></script>
    <input type="file" name="file" id="ipt" />
    <button οnclick="upload(0)">上传</button>
    <script>
      const chunkSize = 1024 * 1024; // 默认分片大小为1兆。1kb = 1024byte, 1m = 1024 kb
      
      function upload(index) {
        const file = ipt.files[0];
        if (!file) return alert("请您先选择要上传的文件~~");
        const { name, type, size } = file;

        // 生成文件hash
        const spark = new SparkMD5.ArrayBuffer();
        spark.append(file);
        const hexHash = spark.end();
        // 生成文件后缀
        const extName = name.substring(name.lastIndexOf("."));
        const startIndex = chunkSize * index;

        // 文件上传完,终止递归同时合并文件
        if (startIndex > size) {
          axios
            .post("http://localhost:9528/merge", {
              fileName: name,
              hexHash,
              extName,
            })
            .then((res) => {
              console.log(res);
            });
          return;
        }
        const endIndex =
          startIndex + chunkSize > size ? size : startIndex + chunkSize;
        const blobPart = file.slice(startIndex, endIndex, type);
        // FormData 直接上传切片后的文件,文件名默认为 blob( filename="blob")
        // 这里通过 File 给个文件名
        const blobFile = new File([blobPart], `${hexHash}-${index}${extName}`, {
          type,
        });
        // 创建虚拟表单进行文件上传
        const vform = new FormData();
        vform.append("vform", blobFile);
        axios.post("http://localhost:9528/upload", vform,{
          onUploadProgress(e) {
              console.log('进度', e.loaded / e.total);
            }
        }).then((res) => {
          // 分片 => 通过递归实现
          upload(++index);
        });
      }
    </script>
  </body>
</html>

server新增路由:

app.post("/merge", function (req, res) {
  const { fileName, hexHash, extName } = req.body;
  const readDir = fs.readdirSync(resolvePath("./temp"));
  readDir.sort((a, b) => a - b).map(chunkPath => {
      fs.appendFileSync(
          resolvePath(`public/${fileName}`),
          fs.readFileSync(resolvePath(`temp/${chunkPath}`))
      );
      fs.rmSync(resolvePath(`temp/${chunkPath}`));
  });
  // fs.rmdirSync(resolvePath("./temp"));
  res.json({
      url: `http://localhost:9528/${fileName}`,
      message: "merge发送成功"
  });
});

测试切片上传:

分片上传完成,服务端就有了这个上传完成视频。

断点续传:

前面在分片上传的时候,每片chunks都有文件唯一性md5code的文件片段${hexHash}-${index}${extName},如果用户选择了重新上传,后端需要根据此文件的 MD5 检索出来文件已经上传的部分,前端续传。

四、补充:

代码都是简易实现的业务逻辑,真正项目上都不用自己手写,GitHub和各大云都有完善的组件库,功能更完善,逻辑更严谨。附地址:

阿里云:如何在OSS中实现分片上传_对象存储 OSS-阿里云帮助中心

腾讯云:对象存储 上传对象-SDK 文档-文档中心-腾讯云

七牛云:JavaScript SDK历史文档1.x_SDK 下载_对象存储 - 七牛开发者中心

百度上传组件:Web Uploader

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83215.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Docker】Docker如何构建自己的镜像?从镜像构建到推送远程镜像仓库图文教程

专栏往期文章 《Docker是什么&#xff1f;Docker从介绍到Linux安装图文详细教程》《30条Docker常用命令图文举例总结》 本期目录专栏往期文章1. 构建镜像2. 本地镜像发布到公有云3. 本地镜像发布到私有云1. 构建镜像 提交构建镜像的命令如下&#xff1a; $ docker commit -m…

大二学生《web课程设计》中华英雄人物介绍袁隆平HTML+CSS+JavaScript(期末考核大作业)

&#x1f389;精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

2021年网络安全省赛--服务器内部信息获取解析(中职组)

2021年省赛服务器内部信息获取解析 任务环境说明:Linux20210510 服务器场景操作系统:未知 (关闭连接) 服务器场景操作系统:Linux(封闭靶机) 用户名:test密码:123456 1.收集服务器场景中的服务信息。并获取服务器中开放的端口号信息,将服务器端口号作为flag提交…

GCN解读并附数据处理代码

此文GCN不是之前提到的lightGCN&#xff0c;而是真正的GCN图卷积&#xff0c;这个问题源于paper分类&#xff0c;同样是GAT所用的数据&#xff0c;其中paper之前的引用关系构成了图的边信息&#xff0c;之所以称之为半监督,并不是因为部分paper没有label及embedding信息&#x…

Nacos--命名空间、分组、ID的概念及用法

原文网址&#xff1a;Nacos--命名空间、分组、ID的概念及用法_IT利刃出鞘的博客-CSDN博客 简介 本文介绍Nacos的命名空间、分组、ID的概念及用法。 Nacos通过命名空间&#xff08;Namespace&#xff09;分组&#xff08;Group&#xff09;应用&#xff08;Data ID或Name&#…

在Maix duino开发板上实现LED闪烁

文章目录简单介绍编程实现效果展示后简单介绍 如果你还不知道如何点亮LED&#xff0c;请看&#xff1a;点亮LED 今天开始上手在开发板上运行程序了&#xff0c;学习点亮LED灯就像是学习编程语言的Hello,worldHello, worldHello,world。学会电亮一盏LED灯之后&#xff0c;我便…

深度学习中计算量和参数量介绍、实现代码、例子

计算量 参数量 模型内存前言1 计算量和参数量2 统计计算量、参数量和模型内存3 源码分享3.1 thop实现3.2 ptflops实现pytorch_model_summary实现各层参数量统计4 总结前言 理清FLOPS和FLOPs&#xff0c;大写S代表的是显卡的运算性能&#xff0c;小写s代表的是模型的运算次数&a…

异构混排在vivo互联网的技术实践

作者&#xff1a;vivo 互联网算法团队- Shen Jiyi 本文根据沈技毅老师在“2022 vivo开发者大会"现场演讲内容整理而成。 混排层负责将多个异构队列的结果如广告、游戏、自然量等进行融合&#xff0c;需要在上下游和业务多重限制下取得最优解&#xff0c;相对复杂和难以控制…

基于外业移动端GIS+CAD在工程行业中的应用

摘要&#xff1a; 本文以广东九建某某高校施工项目前期准备和施工验证工作为依托&#xff0c;以图新地球精准导入CAD为研究对象&#xff0c;总结了一套相对成熟且完善的应用技术。该应用技术能在实际地形和现状数据中迅速找到施工点的大致位置&#xff0c;为前期工程勘测争取足…

【云原生消息中间件】RocketMQ消费者启动(consumer start)流程

目录 一、前言 二、消费者启动(consumer start)流程 1、RocketMQPushConsumer初始化 1.1、InitializingBean的afterPropertiesSet() 实现 1.2、RocketMQPushConsumer初始化 2、DefaultMQPushConsumer#start()逻辑 3、defaultMQPushConsumerImpl.start()逻辑 3.1、预设置…

哈希表题目:“气球”的最大数量

文章目录题目标题和出处难度题目描述要求示例数据范围解法思路和算法代码复杂度分析题目 标题和出处 标题&#xff1a;“气球”的最大数量 出处&#xff1a;1189. “气球”的最大数量 难度 2 级 题目描述 要求 给你一个字符串 text\texttt{text}text&#xff0c;你需要…

无线通信信号传输模型

1. 概述 在移动通信网的规划阶段和网络优化期间&#xff0c;最重要的传播问题是路径损耗&#xff0c;它代表大尺度传播特性&#xff0c;具有幂定律的传播特征。路径损耗是移动通信系统规划设计的一个重要依据&#xff0c;对蜂窝设计中的覆盖范围、信噪比、远近效应都有影响。因…

css色彩主题适配思路

网站主题&#xff0c;之前一直考虑的是通过替换css文件来实现&#xff0c;这种方式虽然可以&#xff0c;但不够方便。毕竟要写两套css主题&#xff0c;需要花费足够多的时间来适配。 后来琢磨出了一点东西出来&#xff0c;发现通过修改root里的css变量来实现&#xff0c;比较优…

计算机研究生就业方向之去银行券商信息技术部门

我一直跟学生们说你考计算机的研究生之前一定要想好你想干什么&#xff0c;如果你只是转码&#xff0c;那么你不一定要考研&#xff0c;至少以下几个职位研究生是没有啥优势的&#xff1a; 1&#xff0c;软件测试工程师&#xff08;培训一下就行&#xff09; 2&#xff0c;前…

NR HARQ(一)概述

HARQ是MAC层的快速重传机制&#xff0c;5G部分HARQ相关内容分布在38.331,38.321,38.213,38.214,38.212,38.211等spec中&#xff0c;这篇仅仅针对NR HARQ 进行简单的概括梳理。 NR中上下行HARQ均为异步HARQ&#xff1b;NR中每个HARQ反馈信息可以针对一个上/下行 TB块&#xff0c…

PDF文件怎么打印?分享两种打印方法

如何将PDF文件打印出来呢&#xff1f;大家在使用PDF文件的时候&#xff0c;在确定一份文件没有问题的时候&#xff0c;会选择将文件打印出来使用&#xff0c;有很多小伙伴身边有打印设备&#xff0c;但是不知道怎么打印&#xff0c;今天小编给大家分享两种打印方法&#xff0c;…

Resolution-robust Large Mask Inpainting with Fourier Convolutions 阅读笔记

基于傅里叶卷积的鲁棒分辨率大Mask修补 WACV 2022 论文链接 代码链接 图1&#xff1a;本文提出的方法可成功修复大区域&#xff0c;并很好处理具有复杂重复结构的图像。该方法在256256低分辨率下训练也能泛化到高分辨率图像上。 摘要&#xff1a; 现代图像修复技术主要受阻于大…

基于intel平台车载M12网管交换机方案,13路网口,支持bypass功能

概述&#xff1a;XM-5130是二层网管型以太网交换机&#xff0c;该产品前面板提供13路100M自适应以太网接口、4路车辆间带链路聚合及bypass功能的以太网接口&#xff0c;接口通过M12端子形式提供。该产品适用于振动、温度、湿度、电源波动变化大、电磁干扰复杂的恶劣工作环境。设…

传统大型国企云原生转型,如何解决弹性、运维和团队协同等问题?

作者&#xff1a;王彬、杏祉尧、黄枫 项目背景 贵州酒店集团有限公司于 2019 年 2 月 28 日注册成立&#xff0c;是经贵州省人民政府批准并授权省国资委履行出资人职责的省管大一型企业&#xff0c;全资及控股子企业 23 家&#xff0c;自营及委管酒店&#xff08;项目&#x…

Nacos的持久化和集群部署

###目前网络模式为&#xff1a;bridge 1.docker mysql:5.7的持久化存储及远程连接 1.下拉镜像 docker pull mysql/mysql-server:5.7 注&#xff1a;后面的mysql标签是版本号&#xff0c;可选择&#xff0c;有&#xff1a;5.5/5.6/5.7/8.0 2.在宿主机中相关目录&#…