文件分块+断点续传 实现大文件上传全栈解决方案(前端+nodejs)

news2024/12/26 22:34:56

1. 文件分块

将大文件切分成较小的片段(通常称为分片或块),然后逐个上传这些分片。这种方法可以提高上传的稳定性,因为如果某个分片上传失败,只需要重新上传该分片而不需要重新上传整个文件。同时,分片上传还可以利用多个网络连接并行上传多个分片,提高上传速度。

2. 断点续传

在上传过程中,如果网络中断或上传被中止,断点续传技术可以记录已成功上传的分片信息,以便在恢复上传时继续上传未完成的部分,而不需要重新上传整个文件。这种技术可以大大减少上传失败的影响,并节省时间和带宽。

3. node项目目录初始化

在这里插入图片描述

  1. 安装依赖

    • express 敏捷启动服务
    • multer 读取文件,存储
    • cors 解决跨域
  2. 目录结构

    • src
      • TED.mp4 (长视频,10分钟,可以下载这个 https://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4
    • uploads 存放切片
    • video 存放将切片拼接后的视频
    • index.html 前端页面

代码附上

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <input id="file" type="file" />
    <script>
      // functions
      // 实现切片的方法
      const makeChunk = (file, size = 1024 * 1024 * 4) => {
        const chunks = [];
        for (let i = 0; i < file.size; i += size) {
          const chunk = file.slice(i, i + size);
          chunks.push(chunk);
        }
        return chunks;
      };

      // 上传分片后的文件方法
      const uploadChunks = (chunks) => {
        // 1. 使用Promise.all保证所有上传方法执行成功
        // 2. 必须要给每个分片文件加标识,才可以让node端进行按序拼接
        const list = [];
        for (let i = 0; i < chunks.length; i++) {
          const formData = new FormData();
          formData.append("filename", "ted");
          formData.append("index", i);
          formData.append("chunk", chunks[i]); // 千万注意,切片文件要最后append否则会出现意外的bug

          list.push(
            fetch("http://localhost:3000/upload", {
              method: "POST",
              body: formData,
            })
          );
        }

        Promise.all(list)
          .then((res) => {
            console.log("上传成功", res);
            fetch("http://localhost:3000/merge", {
              method: "POST",
              headers: {
                "Content-Type": "application/json",
              },
              body: JSON.stringify({
                fileName: "TED演讲10分钟长视频",
              }),
            });
          })
          .catch((err) => {
            console.error("上传失败", err);
          });
      };

      // logic
      const file = document.querySelector("#file");
      file.addEventListener("change", (e) => {
        let file = e.target.files[0]; // 我们只处理单个文件因此取第一个元素即可
        // file是一个对象,底层继承于Blob,借助于Blob身上的slice方法,可以实现对大文件的分片操作
        console.log(file);
        const chunks = makeChunk(file);
        console.log("chunks:", chunks);
        uploadChunks(chunks);
      });
    </script>
  </body>
</html>

index.js

import fs from "node:fs";
import path from "node:path";
import express from "express";
import multer from "multer";
import cors from "cors";

console.log("cors:", cors);

// 1. 初始化multer
const storage = multer.diskStorage({
  // 指定切片存放目录
  destination: function (req, file, cb) {
    cb(null, "../uploads/");
  },
  filename: function (req, file, cb) {
    console.log("req.body.index:", req.body.index);
    console.log("file", file);
    cb(null, `${req.body.filename}-${req.body.index}`);
  },
});

const upload = multer({ storage });

const app = express();
app.use(cors());
app.use(express.json());

// upload.single("chunk") 其中chunk对应前端上传的文件切片名字
app.post("/upload", upload.single("chunk"), (req, res) => {
  console.log("req.body:", req.body);
  res.header("Content-Type", "application/json;charset=utf-8");
  res.send("ok");
});

// 拼接切片
app.post("/merge", (req, res) => {
  // 获取uploadDir的目录
  const uploadDir = path.join(process.cwd(), "../uploads");
  const dirs = fs.readdirSync(uploadDir); // 发现是乱序的
  // 对dirs数组进行排序
  dirs.sort((a, b) => {
    return a.split("-")[1] - b.split("-")[1];
  });
  const videoDir = path.join(
    process.cwd(),
    "../video",
    `${req.body.fileName}.mp4`
  );

  dirs.forEach((item) => {
    // 合并成一个完整的文件至video目录
    fs.appendFileSync(videoDir, fs.readFileSync(path.join(uploadDir, item)));
    // 删除已合并的切片文件
    fs.unlinkSync(path.join(uploadDir, item));
  });
  console.log(dirs);
  res.send("okk");
});

app.listen(3000, () => {
  console.log("server is running at port 3000");
});

最终效果

在这里插入图片描述
在这里插入图片描述

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

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

相关文章

React的路由

1. 什么是前端路由 一个路径 path 对应一个组件 component 当我们在浏览器中访问一个 path 的时候&#xff0c;path 对应的组件会在页面中进行渲染 2. 创建路由开发环境 # 使用CRA创建项目 npm create-react-app react-router-pro# 安装最新的ReactRouter包 npm i react-ro…

AI图书推荐:将 ChatGPT和Excel融合倍增工作效率

《将 ChatGPT和Excel融合倍增工作效率》&#xff08; Hands-on ChatGPT in Excel. Enhance Your Excel Workbooks&#xff09;由Mitja Martini撰写&#xff0c;旨在教授读者如何将ChatGPT与Excel结合使用&#xff0c;以提升工作效率和创造AI增强的Excel工具。它还提供了Excel中…

「中标喜报」合众致达中标深圳安居乐寓智能水电表供货及安装项目

2024年4月25日&#xff0c;深圳合众致达科技有限公司(以下简称“我司”)成功中标安居乐寓2023盐田区保障性租赁住房改造提升项目的水电表供货与安装工程(二次)项目&#xff0c;此次中标标志着我司在城中村公寓出租房能源计费领域的专业实力及市场竞争力得到了进一步的认可。 我…

uniapp视频播放器(h5+app)

关于uniapp视频播放器遇到的一些问题&#xff0c;mark下。 中途遇到了很多问题&#xff0c;如果有相同的伙伴遇到了类似的&#xff0c;欢迎交流 官方的video播放器在app上不友好&#xff0c;有以下功能不支持。 loadedmetadata、controlstoggle不支持导致只能手写控制层。 不…

Pycharm远程连接实验室服务器Conda环境配置

如何配置Pycharm和远程服务器 这类博客较多&#xff0c;参考内容 https://blog.csdn.net/fengbao24/article/details/125515542 Python解释器选择&#xff08;conda3&#xff09; 1. Settings -> Add Interpreter -> On SSH 注意&#xff0c;这里的SSH需要在你把远程…

【TCP:可靠数据传输,快速重传,流量控制,TCP流量控制】

文章目录 可靠数据传输TCP&#xff1a;可靠数据传输TCP发送方事件快速重传流量控制TCP流量控制 可靠数据传输 TCP&#xff1a;可靠数据传输 TCP在IP不可靠服务的基础上建立了rdt 管道化的报文段 GBN or SR 累计确认&#xff08;像GBN&#xff09;单个重传定时器&#xff08;像…

深入浅出TCP 与 UDP

&#x1f525; 引言 在互联网的广阔天地里&#xff0c;TCP&#xff08;Transmission Control Protocol&#xff09;和UDP&#xff08;User Datagram Protocol&#xff09;作为传输层的两大支柱&#xff0c;各自承担着不同的使命。下面这篇文章将带你从基础到进阶&#xff0c;全…

Unity射击游戏开发教程:(8)构建 UI 元素:添加分数显示

用户界面决定用户如何与屏幕交互。UI 适用于所有类型的游戏和应用程序,在此示例中,我们将为我的太空射击游戏设置一个简单的记分板。 第一步是在层次结构中创建一个 UI 元素。只需在层次结构中右键单击,滚动 UI 并选择要添加的 UI 元素类型。在本例中,我们将使用文本元素。…

xLua背包实践

准备工作 环境&#xff0c;代码 在C#代码方面我们需要准备单例模式基类&#xff0c;AB包管理器&#xff0c;lua解析器管理器 详情请见AB包管理器 xlua详解 然后是Xlua包和AB包&#xff0c;具体导入方法也在上面的链接中 然后是lua的三个文件 具体代码&#xff1a; JsonUtil…

必应bing广告可以在国内推广投放了吗?

搜索引擎营销&#xff08;SEM&#xff09;是企业不可或缺的市场拓展手段之一&#xff0c;微软的必应Bing搜索引擎&#xff0c;作为全球第二大搜索引擎&#xff0c;其在中国市场的布局正逐渐显露其独特的价值与潜力。随着必应Bing广告正式对中国市场开放&#xff0c;它不仅为国内…

活动回顾 | 春起潮涌——硬件驱动的量化交易与AI

4月20日&#xff0c;华锐技术ACLUB联合AMD在上海举办了“春起潮涌——硬件驱动的量化交易与AI”沙龙活动&#xff0c;会议围绕FPGA硬件加速、CPU&网卡调优、AI技术应用等展开&#xff0c;近50位量化IT与分享嘉宾一起探讨硬件技术在量化交易和AI领域的应用和创新。 FPGA在交…

SmartEDA助力教学创新:探索未来教育的无限可能

在数字化、智能化的浪潮中&#xff0c;教育领域正经历着前所未有的变革。SmartEDA&#xff0c;作为一款强大的数据分析工具&#xff0c;不仅能够助力科研工作者探索数据的奥秘&#xff0c;还能为教育工作者提供全新的教学手段和思路。本文将探讨如何使用SmartEDA进行教学&#…

Vue3框架

Vue3框架 一.使用create-vue搭建Vue3项目二.组合式API - setup选项1.setup选项的写法和执行时机2.setup中写代码的特点3. script setup 语法糖 三.组合式API - reactive和ref函数1. reactive2. ref3. reactive 对比 ref 四.组合式API - computed五.组合式API - watch1. 侦听单个…

【OC和红移的双面材质】

OC和红移的双面材质 2021-12-23 18:36 rs oc 评论(0)

【酱浦菌-模拟仿真】python模拟仿真PN结伏安特性

PN结的伏安特性 PN结的伏安特性描述了PN结在外部电压作用下的电流-电压行为。这种特性通常包括正向偏置和反向偏置两种情况。 正向偏置 当外部电压的正极接到PN结的P型材料&#xff0c;负极接到N型材料时&#xff0c;称为正向偏置。在这种情况下&#xff0c;外加的正向电压会…

nmap扫描工控设备的脚本支持

参考资料 转自&#xff08;http://www.360doc.com/content/15/1201/11/26186435_517125254.shtml&#xff09; 介绍 NMAP是一款强大的网络扫描工具&#xff0c;除了普通的TCP/IP网络扫描之外&#xff0c;NMAP的扩展脚本功能为我们提供了更为广阔的应用范围。 针对脚本学习可…

构建下一代去中心化应用:基于BASE链的DApp开发

在区块链技术的快速发展中&#xff0c;去中心化应用&#xff08;Decentralized Applications&#xff0c;DApps&#xff09;已经成为了一个热门话题。这些应用通过区块链技术&#xff0c;实现了去中心化、透明、安全和不可篡改的特性&#xff0c;为用户提供了全新的体验和解决方…

js使用echarts图表的柱状图的使用

效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html> <head><title>Bar Chart with Custom Label</title><script src"https://cdn.jsdelivr.net/npm/echarts5.2.2/dist/echarts.min.js"></script> </head&…

Linux编辑器调试器 gcc/g++ gdb 编译过程及使用讲解

这恋爱呀 我有两不谈 第一异性不谈 因为我们性别不一样 我知道的她不知道相处起来太累 第二同性不谈 因为我们性别一样 我知道的他也知道相处起来太无聊了 –❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–…

stm32f103c8t6学习笔记(学习B站up江科大自化协)-UNIX时间戳、BKPRTC

UNIX时间戳 UNIX时间戳最早是在UNIX系统使用的&#xff0c;所以叫做UNIX时间戳&#xff0c;之后很多由UNIX演变而来的系统也继承了UNIX时间戳的规定&#xff0c;目前linux&#xff0c;windows&#xff0c;安卓这些操作系统的底层计时系统都是用UNIX时间戳 时间戳这个计时系统和…