当前位置: 首页 > news >正文

前端大文件分块上传、断点续传

文章目录

  • 前端分块上传流程
  • 分块上传代码
  • 重点
    • 1. `let start = currentChunk * chunkSize;`
    • 2. `let end = Math.min(file.size, start + chunkSize);`
    • 3. `let chunk = file.slice(start, end);`
  • 结合断点续传
  • 注意事项

大文件上传是一个复杂的过程,尤其是在前端,我们需要考虑用户体验、网络状况、文件完整性等多个方面。
以下是一个使用HTML5的 File APIXMLHttpRequest进行大文件分块上传的详解和示例代码。

前端分块上传流程

  1. 选择文件:使用<input type="file">元素让用户选择文件。

  2. 读取文件:使用FileReader API读取文件内容。

  3. 分块文件:根据设定的大小将文件切割成多个小块。

  4. 上传分块:使用XMLHttpRequestfetch API将每个分块上传到服务器。

  5. 合并文件:服务器接收到所有分块后,将其合并成完整的文件。


分块上传代码

以下是一个简单的示例代码,展示了如何使用JavaScript实现大文件的分块上传。

<!DOCTYPE html>  
<html lang="en">  
<head>  <meta charset="UTF-8">  <meta name="viewport" content="width=device-width, initial-scale=1.0">  <title>大文件分块上传</title>  
</head>  
<body>  <input type="file" id="fileInput">  <button id="uploadButton">上传</button>  <script>  const chunkSize = 1024 * 1024; // 每块大小设置为1MB  let fileInput = document.getElementById('fileInput');  let uploadButton = document.getElementById('uploadButton');  uploadButton.addEventListener('click', function () {  let file = fileInput.files[0];  let chunks = Math.ceil(file.size / chunkSize); // 计算文件块数(文件总大小 / 每块大小)let currentChunk = 0; // 当前上传的块数  function uploadChunk() {  if (currentChunk < chunks) {  let start = currentChunk * chunkSize; // 计算当前要上传的分片的起始字节位置(已经上传的字节)let end = Math.min(file.size, start + chunkSize);   // 计算当前要上传的分片的结束字节位置(当前准备上传的字节)let chunk = file.slice(start, end);  let formData = new FormData();  formData.append('chunk', chunk);  formData.append('fileName', file.name);  formData.append('totalChunks', chunks);  formData.append('currentChunk', currentChunk);  let xhr = new XMLHttpRequest();  xhr.open('POST', '/upload', true); // 替换为你的上传接口  xhr.upload.onprogress = function (e) {  // 监听上传进度if (e.lengthComputable) {  console.log((e.loaded / e.total * 100) + '%');  }  };  xhr.onload = function () {  if (xhr.status === 200) {  currentChunk++;  uploadChunk(); // 递归上传下一个块  } else {  console.error('上传失败');  }  };  xhr.send(formData);  } else {  console.log('上传完成');  }  }  uploadChunk(); // 开始上传第一个块  });  </script>  
</body>  
</html>

重点

1. let start = currentChunk * chunkSize;

  • currentChunk当前要上传的文件分片的索引
    如果这是第一个分片,currentChunk 通常是0;如果是第二个分片,它是1,依此类推。
    每当当前分片上传成功,便会累加

  • chunkSize每个分片的大小(以字节为单位)
    这通常是一个固定的值,比如1MB(即1024 * 1024字节)或其他合适的值,取决于你的应用需求和网络条件

  • startcurrentChunkchunkSize 相乘,你得到了当前分片开始的字节位置
    例如,假设你有一个10MB的文件,并且你决定每个分片大小为1MB:
    对于第一个分片(currentChunk = 0),start 会是 0 * 1MB = 0,即从文件的开头开始。
    对于第二个分片(currentChunk = 1),start 会是 1 * 1MB = 1MB,即从文件的1MB位置开始。
    对于第三个分片(currentChunk = 2),start 会是 2 * 1MB = 2MB,以此类推。

.

2. let end = Math.min(file.size, start + chunkSize);

end 是一个变量,用于表示文件分片上传时的结束字节位置。
这个计算确保了分片不会超出文件的实际大小,并且在最后一个分片时能够正确地设置结束位置。

  • start + chunkSize:计算当前分片应该结束的位置,也就是当前需要上传的文件分片

  • file.size:获取文件的总大小

  • Math.min(...):取上述两个值中的较小者作为当前分片的结束位置

这样做的原因是,当处理文件的最后一个分片时,start + chunkSize 可能会超出文件的实际大小。
为了避免这种情况,我们使用 Math.min 函数来确保 end 不会大于文件的实际大小(file.size)。

或者可以这么理解: let end = start + chunkSize > file.size ? file.size : start + chunkSize

例如,假设你有一个13MB的文件,并且你决定每个分片大小为5MB。即:

  • file.size = 13*1024*1024 => 文件大小为 13631488 字节

  • chunkSize = 5*1024*1024 => 每个分片大小为 5242880 字节

  • let chunks = Math.ceil(file.size / chunkSize) => 文件块数为3

这时:

  • 第一个分片:start + chunkSize 将分别是 0 + 5MB

  • 第二个分片:start + chunkSize 将分别是 5MB + 5MB

  • 第三个分片:如果简单地使用 10MB + 5MB,你会得到一个超出文件大小的结束位置(15MB>13MB)。
    通过 Math.min,你可以确保第三个分片的结束位置正确地设置为文件的末尾(即13MB):
    Math.min(file.size, start + chunkSize) => Math.min(13*1024*1024, (10+5)*1024*1024) => 13*1024*1024 字节 => 13MB

.

3. let chunk = file.slice(start, end);

在JavaScript中,file.slice(start, end) 是 Blob 对象的一个方法,用于创建一个新的 Blob 对象,该对象包含源 Blob 对象中指定范围内的数据。这通常用于文件操作,特别是当你需要处理文件的一部分(例如,分片上传)时。

file 是一个 Blob 或 File 对象(File 继承自 Blob),而 start 和 end 是指定切片范围的参数:

  • start(包含):开始切片的字节偏移量。
  • end(不包含):结束切片的字节偏移量。(如果 end 被省略或大于 Blob 的大小,则切片会一直到 Blob 的末尾。)

例如,如果你有一个 File 对象 file,你可以使用 slice 方法来获取文件的部分字节

var slice1 = file.slice(0, 100);  // 获取文件的前100个字节var slice2 = file.slice(100, 200); // 获取从第101个字节开始到第200个字节结束的部分

注意:

  • slice 方法不会改变原始的 Blob 或 File 对象
  • 它返回一个新的 Blob 对象,该对象包含指定范围内的数据

结合断点续传

断点续传(Resume Download)是一种在网络传输中常见的功能,它允许在下载大文件时,如果由于某种原因(如网络中断、程序崩溃等)导致下载中断,可以从之前中断的地方继续下载,而不是重新下载整个文件。这可以大大节省时间和带宽资源。

// 假设你已经通过某种方式获取了文件对象以及要续传的起始字节位置 startByte  
const file = document.querySelector('input[type="file"]').files[0];  
const chunkSize = 1024 * 1024; // 1MB 分片大小  
const startByte = // 从服务器获取的已下载字节数,用于断点续传  
let currentChunk = Math.ceil(startByte / chunkSize); // 计算当前应该开始下载的分片索引  // 分片函数  
function createChunk(file, start, end) {  const chunk = file.slice(start, end);  return new Blob([chunk], { type: file.type });  
}  // 创建分片并发送请求的函数  
function uploadChunk(chunk, chunkIndex) {  const formData = new FormData();  formData.append('file', chunk);  formData.append('chunkIndex', chunkIndex);  formData.append('fileName', file.name);  formData.append('chunkSize', chunkSize);  formData.append('totalSize', file.size);  axios.post('/upload-chunk', formData, {  headers: {  'Content-Type': 'multipart/form-data'  },  onUploadProgress: progressEvent => {  const percentCompleted = Math.round((progressEvent.loaded * 100) / progressEvent.total);  console.log(`Chunk ${chunkIndex + 1} uploaded: ${percentCompleted}%`);  },  onDownloadProgress: progressEvent => {  // 可以在这里处理下载进度,如果需要的话  }  })  .then(response => {  if (response.data.success) {  console.log(`Chunk ${chunkIndex + 1} uploaded successfully.`);  // 检查是否所有分片都已上传完成  if (chunkIndex < Math.ceil(file.size / chunkSize) - 1) {  // 上传下一个分片  const nextChunkStart = chunkIndex * chunkSize + chunkSize;  const nextChunkEnd = Math.min(nextChunkStart + chunkSize, file.size);  const nextChunk = createChunk(file, nextChunkStart, nextChunkEnd);  uploadChunk(nextChunk, chunkIndex + 1);  } else {  // 所有分片上传完成,可以通知服务器合并文件或进行其他操作  console.log('All chunks uploaded successfully.');  }  } else {  console.error('Chunk upload failed:', response.data.error);  }  })  .catch(error => {  console.error('Chunk upload error:', error);  // 可以在这里处理错误,比如重试上传当前分片或全部重新开始  });  
}  // 开始上传  
const firstChunkStart = currentChunk * chunkSize;  
const firstChunkEnd = Math.min(firstChunkStart + chunkSize, file.size);  
const firstChunk = createChunk(file, firstChunkStart, firstChunkEnd);  
uploadChunk(firstChunk, currentChunk);

在这个示例中:

  • createChunk 函数用于创建文件的分片

  • uploadChunk 函数用于发送包含分片数据的 POST 请求到服务器

  • startByte 是从服务器获取的已下载字节数,用于确定从哪里开始上传分片

每次上传一个分片后,如果成功,则检查是否还有剩余的分片需要上传,如果有,则继续上传下一个分片。

请注意,这个示例仅涵盖了前端的部分逻辑。为了实现完整的断点续传功能,你还需要在后端实现相应的逻辑来处理分片上传、合并分片以及存储和检索已上传的分片信息。此外,还需要考虑如何安全地验证和授权上传请求,以避免安全风险。


注意事项

  1. 文件完整性校验:上传完成后,服务器需要对合并后的文件进行完整性校验,确保文件没有损坏。

  2. 断点续传:在实际应用中,还需要考虑断点续传的功能,即当上传中断时,可以从上次中断的地方继续上传。

  3. 上传进度显示:在上传过程中,可以通过XMLHttpRequestupload.onprogress事件来显示上传进度。

  4. 错误处理:在上传过程中可能会遇到各种错误,如网络错误、服务器错误等,需要妥善处理这些错误,并给用户友好的提示。

  5. 安全性:在处理文件上传时,需要注意安全性问题,如防止恶意文件上传、防止跨站脚本攻击等。

相关文章:

前端大文件分块上传、断点续传

文章目录 前端分块上传流程分块上传代码重点1. let start currentChunk * chunkSize;2. let end Math.min(file.size, start chunkSize);3. let chunk file.slice(start, end); 结合断点续传注意事项 大文件上传是一个复杂的过程&#xff0c;尤其是在前端&#xff0c;我们需…...

使用新版FLIR (FLIR_ADAS_v2) 数据集创建yolo格式数据集(目标检测)

FLIR在2022.1.19发布了新版的FLIR_ADAS_v2&#xff0c;有着更多的类别和数量更丰富的图像。数据集同步注释热图像和无注释RGB图像供参考。本文章主要介绍如何使用FLIR_ADAS_v2中的rgb图像和thermal图像来制作yolo格式数据集。 1.官方数据集下载&#xff1a;FLIR_ADAS_v2数据集…...

PHP发票查验接口未返回正确信息的原因、发票ocr识别接口

发票查验接口未返回正确信息的原因一般有以下几种&#xff0c;第一种可能是接口没有调通&#xff0c;第二种是本身这张发票就是一张错票、假票&#xff0c;第三种可能是税局系统或者网络问题等等。那么&#xff0c;遇到这种情况应该如何解决呢&#xff1f;翔云发票查验接口&…...

RA4000CE为汽车动力传动系统提供解决方案

目前汽车电气化的水平越来越高&#xff0c;其中比较显著的一个发展方向就是将发动机管理系统和自动变速器控制系统&#xff0c;集成为动力传动系统的综合控制(PCM)。作为汽车动力的核心部件&#xff0c;通过电子系统的运用&#xff0c;将外部多个传感器和执行环节的数据进行统一…...

算法中的二阶差分

众所周知&#xff0c;在往区间的每一个数都加上一个相同的数k&#xff0c;进行n次后会得到一个新的数列&#xff0c;如果每次加都循环区间挨个数加上k&#xff0c;这样时间复杂度无疑是O(n^2)&#xff0c;很高。这时可以采用一阶差分就可解决&#xff0c;这里默认会一阶差分&am…...

第十五届蓝桥杯Java A组参赛总结

一、比赛 4月13号那天上午9点到下午1点&#xff0c;线上比赛总共4小时。 因为很久没有参加过竞赛了&#xff0c;所以还是很紧张&#xff0c;睡觉都有点睡不好&#xff0c;生怕出什么差错 我参加的是java的A组&#xff0c;两道填空&#xff08;每道5分&#xff09;和六道大题…...

springCloudAlibaba集成seata实战(分布式事物详解)

一、分布式事务 1. 事务介绍 1.1 基础概念 事务&#xff1a;保证我们多个数据库操作的原子性&#xff0c;多个操作要么都成功要么都不成功 事务ACID原则 A&#xff08;Atomic&#xff09;原子性&#xff1a;构成事务的所有操作&#xff0c;要么都执行完成&#xff0c;要么全部…...

VRTK/SteamVR手柄震动功能

VRTK/SteamVR手柄震动功能 前言代码块 前言 手柄震动功能配合虚拟仿真模块的模拟电击等功能非常方便 代码块 SteamVR_Controller.DeviceRelation.Rightmost是右侧手柄 SteamVR_Controller.DeviceRelation.Leftmost是左侧手柄 var deviceIndex2 SteamVR_Controller.GetDevic…...

MYSQL索引优化方法

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是小周同志&#xff0c;25届双非校招生Java选手&#xff0c;很高兴认识大家 &#x1f4d5;学习出处&#xff1a;本文是学自小林coding (xiaolincoding.com) 网站的MYSQL图解篇 &#x1f525;如果感觉博主的文章还不错的…...

多模态 ——LLaVA 集成先进图像理解与自然语言交互GPT-4的大模型

概述 提出了一种大型模型 LLaVA&#xff0c;它使用 GPT-4 生成多模态语言图像指令跟随数据&#xff0c;并利用该数据将视觉和语言理解融为一体。初步实验表明&#xff0c;LLaVA 展示了出色的多模态聊天能力&#xff0c;在合成多模态指令上的表现优于 GPT-4。 在科学质量保证中…...

文献学习-33-一个用于生成手术视频摘要的python库

VideoSum: A Python Library for Surgical Video Summarization Authors: Luis C. Garcia-Peraza-Herrera, Sebastien Ourselin, and Tom Vercauteren Source: https://arxiv.org/pdf/2303.10173.pdf 这篇文章主要关注的是如何通过视频摘要来简化和可视化手术视频&#xff0c…...

Unity Android 2021 Release-Notes

&#x1f308;Unity Android 2021 Release-Notes 版本更新内容2021.3.34Android: Google play.core package is replaced with separate plugins including play.asset-delivery 2.1.0 to solve PAD related compatibility problem with Android 14.(UUM-54157)2021.3.34Androi…...

Java8新特性--lambda表达式

lambda表达式本质上是一个匿名函数&#xff0c;在lambda表达式中我们只需要关心参数列表以及方法体。优点是可以减少代码量。 1.语法 基本语法&#xff1a;(参数)->表达式 或 (参数) -> {语句;} 2.函数式接口 要了解lambda表达式&#xff0c;首先要了解什么是函数式接口…...

C/C++中设置随机数

前言 我们通常在写一个数据结构后&#xff0c;需要去测试其正确性和性能比较&#xff0c;那在平常手动输入数据的方式太鸡肋&#xff0c;并且不具有普遍性和随机性。基于这个原因&#xff0c;我们必须要掌握设置随机数&#xff0c;不但可以给我们提供更多的数据&#xff0c;还可…...

ARM 三个小灯闪烁

.text .global _start _start: 使能GPIOE的外设时钟 LDR R0,0x50000A28 指定基地址 LDR R1,[R0] 读取r0中的数据保存到r1中 ORR R1,R1,#(0X3<<4) [4]设置为1,表示 STR R1,[R0] 将修改之后的值放回去 设置PE10,PE8为输出 LDR R0,0X50006000…...

创业之路:从市场洞察到产品实现的全方位指南

创业是一项挑战性的旅程&#xff0c;需要综合考虑市场、产品、技术、团队等多个方面。在这篇文章中&#xff0c;我们将深入探讨如何更好地进行创业&#xff0c;从市场分析到产品实现的各个环节。 深入市场洞察 在创业之前&#xff0c;深入了解目标市场是至关重要的。我们需要…...

C++ 红黑树模拟实现

&#x1f493;博主CSDN主页:麻辣韭菜&#x1f493;   ⏩专栏分类&#xff1a;C知识分享⏪   &#x1f69a;代码仓库:C高阶&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C知识   &#x1f51d;&#x1f51d; 前言 前面我们实现了AVL树&#xff0c;发明AVL树…...

【数据结构】第三节:单链表

前言 本篇要求掌握的C语言基础知识&#xff1a;指针、结构体 目录 前言 单链表 概念 对比链表和顺序表 创建链表 实现单链表 准备工作 打印链表 创建节点并初始化 尾插 二级指针的调用 尾插代码 头插 尾删 头删 查找&#xff08;返回节点&#xff09; 在指定位…...

Python中操作Excel表对象并打包为脚本

一、准备工作 pip install pandas pip install openpyxl pip install pyinstaller 数据表格&#xff1a; 数据表下载 二、执行写入操作 import pandas as pd # pyinstaller --onefile attendance_records_score.py # 打包 # 读取源Excel文件&#xff08;假设源表有列A…...

Python学习笔记23 - 目录操作

os模块操作目录相关函数 os.path模块操作目录相关函数 案例1 —— 列出指定目录下的所有.py文件 案例2 —— walk()...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

java 实现excel文件转pdf | 无水印 | 无限制

文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

Rapidio门铃消息FIFO溢出机制

关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系&#xff0c;以下是深入解析&#xff1a; 门铃FIFO溢出的本质 在RapidIO系统中&#xff0c;门铃消息FIFO是硬件控制器内部的缓冲区&#xff0c;用于临时存储接收到的门铃消息&#xff08;Doorbell Message&#xff09;。…...

HTML中各种标签的作用

一、HTML文件主要标签结构及说明 1. <&#xff01;DOCTYPE html> 作用&#xff1a;声明文档类型&#xff0c;告知浏览器这是 HTML5 文档。 必须&#xff1a;是。 2. <html lang“zh”>. </html> 作用&#xff1a;包裹整个网页内容&#xff0c;lang"z…...

C#最佳实践:为何优先使用as或is而非强制转换

C#最佳实践&#xff1a;为何优先使用as或is而非强制转换 在 C# 的编程世界里&#xff0c;类型转换是我们经常会遇到的操作。就像在现实生活中&#xff0c;我们可能需要把不同形状的物品重新整理归类一样&#xff0c;在代码里&#xff0c;我们也常常需要将一个数据类型转换为另…...

Unity VR/MR开发-开发环境准备

视频讲解链接&#xff1a; 【XR马斯维】UnityVR/MR开发环境准备【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...

多层PCB技术解析:从材料选型到制造工艺的深度实践

在电子设备集成度与信号传输要求不断提升的背景下&#xff0c;多层PCB凭借分层布局优势&#xff0c;成为高速通信、汽车电子、工业控制等领域的核心载体。其通过导电层、绝缘层的交替堆叠&#xff0c;实现复杂电路的立体化设计&#xff0c;显著提升空间利用率与信号完整性。 一…...

ai流式文字返回前端和php的处理办法

PHP后端 php端主要是用到ob_flush和flush&#xff0c;头改为流式。 基本代码 代码如下&#xff1a; <?php header(Content-Type:text/event-stream); header(Cache-Control:no-cache); header(Connection:keep-alive);function streamPostRequest($url,$data){$chcurl_…...