【文件上传】✈️大文件的上传服务器的简单实现

news2025/7/13 20:23:55

💥💥✈️✈️欢迎阅读本文章❤️❤️💥💥

🏆本篇文章阅读大约耗时五分钟

⛳️motto:不积跬步、无以千里

📋📋📋本文目录如下:🎁🎁🎁

目录

前言

简述

实现

测试

章末

前言

        小伙伴们大家好,上周闲暇之余在本地测试部署了几个开源项目,没什么大问题,开源项目是真的很开源,项目报告论文一并齐全!文章链接如下:

【项目部署】✈️普通 SpringBoot 项目拿到源码后怎么在本地部署启动

【项目部署】⭐️基于 SpringBoot 的医护人员排版系统的部署

        这篇文章接着了解下开发中常见的需求,文件上传功能,允许系统的用户将本地文件通过网络传输到系统服务器上(当然,也可以不直接存储在服务器,现在有很多对象存储服务,比如 阿里的 oss, 华为的 obs 服务,都可以存储文件,使用也很方便),但是如果是特别大的文件并且不进行控制,可能会对服务器造成一系列影响,常见的影响有很多:增加服务器负担,导致服务器响应缓慢等;针对以上情况,现在有很多处理方式,比如分片上传方案

简述

        何为分片?简单讲就是将大文件分成多个较小的文件,然后依次或者并行将这些上传到服务器的过程;等所有的分片文件上传完毕之后,服务器可以将其合并为原始文件

        另外可以调研下分片过程中出现异常导致部分文件上传失败,需要怎么处理,感觉可以根据分片的序列号记录,找到未上传成功的那部分,再重试上传,这样也可以避免传统整个文件上传失败导致全部要重新上传(有时间再去调研下吧,先这样了)

实现

        正如上面所讲,分片需要前端处理好文件的分割,后端提供相应的上传接口,所以本地就简单模拟下操作页面(不要在意页面的简陋哈)

        1、前端页面(uploadBigFile.html)

        只有三个按钮,选择文件可以自定义选择要上传的文件

        上传文件这里会将文件按照指定大小分割文件并调用上传接口

        合并文件会触发后端服务将对应上传完成的分片文件合并为原始文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>文件上传</title>
  <style>
    body {
      font-family: Arial, sans-serif;
    }
    h2 {
      color: #333;
    }
    input, button {
      margin: 10px 0;
    }
  </style>
</head>
<body>

<div id="app">
  <h2>文件上传</h2>

  <!-- 文件选择 -->
  <input type="file" id="fileInput" />
  <br><br>

  <!-- 上传按钮 -->
  <button id="uploadBtn">上传文件</button>
  <br><br>

  <!-- 合并文件按钮 -->
  <button id="mergeBtn">合并文件</button>
</div>

<script>
  document.getElementById('uploadBtn').addEventListener('click', uploadFile);
  document.getElementById('mergeBtn').addEventListener('click', mergeFile);

  let fileName = ''; // 用于存储文件名

  // 上传文件(分块上传)
  function uploadFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];

    if (!file) {
      alert('请选择一个文件');
      return;
    }

    fileName = file.name;
    uploadFileInChunks(file);
  }

  // 将文件分块上传
  function uploadFileInChunks(file) {
    const chunkSize = 1024 * 1024 * 2; // 每个块的大小是 2MB
    let start = 0;
    let chunkIndex = 0;

    while (start < file.size) {
      const chunk = file.slice(start, start + chunkSize);
      console.log(`上传第 ${chunkIndex} 块`);
      uploadChunk(chunk, chunkIndex);
      start += chunkSize;
      chunkIndex++;
    }
  }

  // 上传每一块文件
  function uploadChunk(chunk, chunkIndex) {
    const formData = new FormData();
    formData.append('chunk', chunk);
    formData.append('chunkIndex', chunkIndex);
    formData.append('fileName', fileName);

    fetch('http://localhost:8890/upload-chunk', {
      method: 'POST',
      body: formData
    })
            .then(response => response.json())
            .then(data => {
              console.log(data);
            })
            .catch(error => {
              console.error('上传失败:', error);
            });
  }

  // 合并文件
  function mergeFile() {
    const formData = new FormData();
    formData.append('fileName', fileName);

    fetch('http://localhost:8890/merge-chunks', {
      method: 'POST',
      body: formData
    })
            .then(response => response.json())
            .then(data => {
              console.log('文件合并成功', data);
            })
            .catch(error => {
              console.error('合并失败:', error);
            });
  }
</script>

</body>
</html>

        2、后端接口

        后端接口是直接将文件存储在本地指定文件夹下的

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;

/**
 * @author HuangBenben 
 */
@RestController
public class ChunkController {

    // 临时文件存储目录
    private static final String TEMP_DIR = "C:\\Data\\extFiles\\temp\\";


    // 合并后文件存储目录
    private static final String TARGET_DIR = "C:\\Data\\extFiles\\final\\";

    /**
     * 处理文件分块上传
     * 
     * @param chunk 文件块
     * @param chunkIndex 当前块的索引
     * @param fileName 文件名
     * @return 返回上传状态信息
     * @throws IOException 如果发生IO异常
     */
    @PostMapping("/upload-chunk")
    public ResponseEntity<String> uploadChunk(
            @RequestParam("chunk") MultipartFile chunk,
            @RequestParam("chunkIndex") int chunkIndex,
            @RequestParam("fileName") String fileName) throws IOException {

        // 创建目录结构,如果不存在则创建
        File dir = new File(TEMP_DIR + fileName);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 创建当前分块的文件
        File chunkFile = new File(dir, "chunk_" + chunkIndex);

        // 写入文件分块数据
        try (OutputStream os = new FileOutputStream(chunkFile)) {
            os.write(chunk.getBytes());
        }

        // 返回成功消息
        return ResponseEntity.ok("Chunk " + chunkIndex + " uploaded successfully.");
    }


    /**
     * 合并文件分块
     *
     * @param fileName 文件名
     * @return 合并完成的响应
     * @throws IOException 如果发生IO异常
     */
    @PostMapping("/merge-chunks")
    public ResponseEntity<String> mergeChunks(@RequestParam("fileName") String fileName) throws IOException {

        // 获取存储文件块的临时目录
        File dir = new File(TEMP_DIR + fileName);

        // 创建合并后的目标文件
        File mergedFile = new File(TARGET_DIR + fileName);

        // 合并文件块
        try (OutputStream os = new FileOutputStream(mergedFile)) {
            // 遍历目录中的所有文件块并合并
            for (int i = 0, len = dir.listFiles().length; i < len; i++) {
                File chunkFile = new File(dir, "chunk_" + i);

                // 将文件块写入合并文件中
                Files.copy(chunkFile.toPath(), os);

                // 删除已经处理过的文件块
                chunkFile.delete();
            }
        }

        // 删除临时目录(所有文件块处理完后)
        dir.delete();

        // 返回合并完成的响应
        return ResponseEntity.ok("文件合并完成");
    }
}

        3、配置调整

        按照 SpringBoot  的默认配置,单次请求的文件上限是 1MB,如下,不更改配置的应该会遇到这个异常

Resolved [org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException: The field chunk exceeds its maximum permitted size of 1048576 bytes.]

        可以在配置中调整下上限,如下:

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB

测试

        简单看下,启动项目后先访问到静态资源,然后选择一个要上传的文件(本地上传的是一个 5 MB 左右的文档)

        上传文件

         每片文件大小 2MB ,分了三片上传,文件分割没问题,接口相应成功,去对应的文件夹下看看是否存储成功,检查下对应的是否有三个文件

         合并文件

        检查下接口响应正常,看下是否有原始文件,并且内容是否和源文件是否一致

         ok 测试没问题,并且在合并文件之后,对应文件的分片文件也已经删除了

章末

        文章到这里就结束了~

往期推荐 > > > 

 【接口负载】✈️整合 Resilience4j 指定接口负载,避免过载

 【SpringBoot】⭐️整合 Redis 实现百万级数据实时排序

 【SpringBoot】✈️本地集成支付宝支付功能

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

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

相关文章

Windows DOS窗口12个命令

DOS 命令是指在 Windows 命令提示符&#xff08;CMD&#xff09;中使用的命令行工具&#xff0c;源于早期的 Disk Operating System。虽然现代 Windows 系统更多使用图形界面&#xff0c;但命令提示符仍然是测试人员的重要工具。测试人员通常需要执行文件操作、测试网络连接、监…

AI加Python的文本数据情感分析流程效果展示与代码实现

本文所使用数据来自于梯田景区评价数据。 一、数据预处理 数据清洗 去除重复值、空值及无关字符(如表情符号、特殊符号等)。 提取中文文本,过滤非中文字符。 统一文本格式(如全角转半角、繁体转简体)。 中文分词与去停用词 使用 jieba 分词工具进行分词。 加载自定义词…

docker启动nacos+redis+seata

docker启动nacos 最新版本的nacos需要再启动的时候设置mysql的一些属性&#xff0c;【也可以先启动nacos&#xff0c;再到配置文件中找到application.yml设置mysql的一些属性】。 1.如果直接启动nacos设置的mysql我们需要确定两个容器的ip都是一样的。 查看mysql容器中的ip命令…

从 select 到 epoll:拆解 I/O 多路复用的演进与实战

目录 一、引言&#xff1a;为什么需要 I/O 多路复用&#xff1f; 二、select 1.函数介绍 2.原理 3.样例代码 4.优缺点总结 三、poll 1.函数介绍 2.样例代码 3.优缺点总结 四、epoll 1.函数介绍 2.原理 3.LT和ET两种工作模式 4.优缺点总结 五、核心机制对比&…

【力扣hot100题】(017)矩阵置零

还是挺简单的&#xff0c;使用哈希表记录需要置换的行列即可&#xff0c;这样就可以避免重复节省时间。 class Solution { public:void setZeroes(vector<vector<int>>& matrix) {unordered_set<int> row;unordered_set<int> line;for(int i0;i&l…

One Commander 3,文件管理新体验

One Commander 3 是一款集多功能于一体 Windows 10/11的文件管理工具&#xff0c;其设计目的在于为用户带来多元化的操作体验。这款工具通过支持多栏界面布局&#xff0c;让用户能够迅速且高效地组织和管理文件。此外&#xff0c;它还提供了多主题选项和多种图标集&#xff0c;…

非手性分子发光有妙招:借液晶之力,实现高不对称圆偏振发光

*本文只做阅读笔记分享* 一、圆偏振发光研究背景与挑战 圆偏振发光&#xff08;CPL&#xff09;材料在3D显示、光电器件等领域大有用处&#xff0c;衡量它的一个重要指标是不对称发光因子&#xff08;glum&#xff09;。早期CPL材料的glum值低&#xff0c;限制了实际应用。为…

YOLOv8+ Deepsort+Pyqt5车速检测系统

该系统通过YOLOv8进行高效的目标检测与分割&#xff0c;结合DeepSORT算法完成目标的实时跟踪&#xff0c;并利用GPU加速技术提升处理速度。系统支持模块化设计&#xff0c;可导入其他权重文件以适应不同场景需求&#xff0c;同时提供自定义配置选项&#xff0c;如显示标签和保存…

【干货】前端实现文件保存总结

⚠️⚠️文前推荐一下&#x1f449; 前端必备工具推荐网站(图床、API和ChatAI、智能AI简历、AI思维导图神器等实用工具): 站点入口&#xff1a;http://luckycola.com.cn/ 前端实现文件保存实现总结 在Web开发中&#xff0c;文件下载是常见的交互需求。本文将系统总结前端实现文…

并发编程之FutureTask.get()阻塞陷阱:深度解析线程池CPU飚高问题排查与解决方案

FutureTask.get方法阻塞陷阱&#xff1a;深度解析线程池CPU飚高问题排查与解决方法 FutureTask.get()方法阻塞陷阱&#xff1a;深度解析线程池CPU飚高问题排查与解决方法1、情景复现1.1 线程池工作原理1.2 业务场景模拟1.3 运行结果1.4 发现问题&#xff1a;线程池没有被关闭1.…

在Ubuntu中固定USB设备的串口号

获取设备信息 lsusb # 记录设备的Vendor ID和Product ID&#xff08;例如&#xff1a;ID 0403:6001&#xff09;# 获取详细属性&#xff08;替换X和Y为实际设备号&#xff09; udevadm info -a /dev/ttyUSBX 结果一般如下 创建udev规则文件 sudo gedit /etc/udev/rules.d/us…

javaSE————文件IO(2)、

文件内容的读写——数据流 我们对于文件操作使用流对象Stream来操作&#xff0c;什么是流对象呢&#xff0c;水流是什么样的&#xff0c;想象一下&#xff0c;水流的流量是多种的&#xff0c;可以流100ml&#xff0c;也可以流1ml&#xff0c;流对象就和水流很像&#xff0c;我…

前端常问的宏观“大”问题详解(二)

JS与TS选型 一、为什么选择 TypeScript 而不是 JavaScript&#xff1f; 1. 静态类型系统&#xff1a;核心优势 TypeScript 的静态类型检查能在 编译阶段 捕获类型错误&#xff08;如变量类型不匹配、未定义属性等&#xff09;&#xff0c;显著减少运行时错误风险。例如&…

智慧电力:点亮未来能源世界的钥匙

在科技日新月异的今天&#xff0c;电力行业正经历着前所未有的变革。智慧电力&#xff0c;作为这一变革的核心驱动力&#xff0c;正逐步改变着我们对电力的认知和使用方式。它不仅是电力行业的一次技术革新&#xff0c;更是推动社会可持续发展、实现能源高效利用的重要途径。 智…

架构师面试(二十三):负载均衡

问题 今天我们聊微服务相关的话题。 大中型微服务系统中&#xff0c;【负载均衡】是一个非常核心的组件&#xff1b;在微服务系统的不同位置对【负载均衡】进行了实现&#xff0c;下面说法正确的有哪几项&#xff1f; A. LVS 的负载均衡一般通过前置 F5 或是通过 VIP keepa…

NSSCTF(MISC)—[justCTF 2020]pdf

相应的做题地址&#xff1a;https://www.nssctf.cn/problem/920 binwalk分离 解压文件2AE59A.zip mutool 得到一张图片 B5F31内容 B5FFD内容 转换成图片 justCTF{BytesAreNotRealWakeUpSheeple}

坚持“大客户战略”,昂瑞微深耕全球射频市场

北京昂瑞微电子技术股份有限公司&#xff08;简称“昂瑞微”&#xff09;是一家聚焦射频与模拟芯片设计的高新技术企业。随着5G时代的全面到来&#xff0c;智能手机、智能汽车等终端设备对射频前端器件在通信频率、多频段支持、信道带宽及载波聚合等方面提出了更高需求&#xf…

LiteDB 数据库优缺点分析与C#代码示例

LiteDB 是一个轻量级的 .NET NoSQL 嵌入式数据库,完全用 C# 开发,支持跨平台(Windows、Linux、MacOS),并提供类似于 MongoDB 的简单 API。它以单文件形式存储数据,类似于 SQLite,支持事务和 ACID 特性,确保数据的一致性和可靠性。 优缺点分析 优点: 轻量级与嵌入式:…

Linux系统中快速安装docker

1 查看是否安装docker 要检查Ubuntu是否安装了Docker&#xff0c;可以使用以下几种方法&#xff1a; 方法1&#xff1a;使用 docker --version 命令 docker --version如果Docker已安装&#xff0c;输出会显示Docker的版本信息&#xff0c;例如&#xff1a; Docker version …

CP15 协处理器

ARMv7-A 一共支持 16 个协处理器&#xff0c;编号从 CP0~CP15。这里仅对CP15进行描述。 1、ARMv7-A 协处理器 ARMv7-A 处理器除了标准的 R0~R15&#xff0c;CPSR&#xff0c;SPSR 以外&#xff0c;由于引入了 MMU、TLB、Cache 等内容&#xff0c;ARMv7-A 使用协处理器来对这些…