首页 > 其他分享 >文件分片和断点虚传

文件分片和断点虚传

时间:2023-12-11 11:05:54浏览次数:24  
标签:chunkNumber 断点 分片 虚传 file totalChunks 上传 fileId


前端代码

要优化前端的文件分片上传代码,我们可以考虑以下几点:

  1. 异步上传与并发控制:上传分片时使用异步请求,并控制同时上传的分片数量,避免同时发送过多请求导致浏览器或服务器压力过大。
  2. 上传进度显示:向用户显示每个分片的上传进度和总体进度。
  3. 断点续传:在上传之前检查哪些分片已经上传过,只上传未完成的分片。
  4. 错误处理与重试机制:对于上传失败的分片,实现自动重试逻辑。

以下是优化后的前端代码示例:

HTML 部分
<!DOCTYPE html>
<html>
<head>
    <title>File Upload</title>
</head>
<body>
    <input type="file" id="fileInput">
    <button onclick="uploadFile()">Upload</button>
    <div id="uploadStatus"></div>
    <progress id="uploadProgress" value="0" max="100"></progress>
</body>
</html>
JavaScript 部分
const MAX_CONCURRENT_UPLOADS = 5;  // 最大并发上传数
let concurrentUploads = 0;        // 当前并发上传数
let fileChunksQueue = [];         // 待上传的文件分片队列

function uploadFile() {
    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];
    var chunkSize = 1024 * 1024; // 分片大小,这里设置为 1MB
    var totalChunks = Math.ceil(file.size / chunkSize);

    // 初始化分片队列
    for (let i = 0; i < totalChunks; i++) {
        let start = i * chunkSize;
        let end = Math.min(file.size, start + chunkSize);
        let chunk = file.slice(start, end);

        fileChunksQueue.push({ chunk, chunkNumber: i + 1, totalChunks, fileName: file.name });
    }

    // 开始上传
    startUploads();
}

function startUploads() {
    while (concurrentUploads < MAX_CONCURRENT_UPLOADS && fileChunksQueue.length > 0) {
        const chunkData = fileChunksQueue.shift();
        uploadChunk(chunkData);
        concurrentUploads++;
    }
}

function uploadChunk({ chunk, chunkNumber, totalChunks, fileName }) {
    var formData = new FormData();
    formData.append('file', chunk);
    formData.append('chunkNumber', chunkNumber);
    formData.append('totalChunks', totalChunks);
    formData.append('fileId', fileName);

    fetch('http://localhost:8080/file/upload', {
        method: 'POST',
        body: formData
    })
    .then(response => response.text())
    .then(data => {
        concurrentUploads--;
        updateUploadStatus(chunkNumber, totalChunks);
        startUploads(); // 继续上传下一个分片
    })
    .catch(error => {
        console.error('Error:', error);
        fileChunksQueue.push({ chunk, chunkNumber, totalChunks, fileName }); // 重试
        concurrentUploads--;
        startUploads();
    });
}

function updateUploadStatus(chunkNumber, totalChunks) {
    let uploadedChunks = chunkNumber;
    let progress = (uploadedChunks / totalChunks) * 100;
    document.getElementById('uploadProgress').value = progress;
    document.getElementById('uploadStatus').innerHTML = `Uploaded ${uploadedChunks} of ${totalChunks} chunks (${progress.toFixed(2)}%)`;
}

优化点说明

  • 并发控制:通过 MAX_CONCURRENT_UPLOADS 控制同时上传的分片数量。
  • 上传队列:使用 fileChunksQueue 管理待上传的分片队列。
  • 进度显示:使用 HTML progress 元素显示上传进度。
  • 错误处理与重试:上传失败的分片会被重新放回队列中等待重试。

这种优化可以提高上传效率,同时提供更好的用户体验。还可以根据需要进一步增加例如上传失败后的最大重试次数等更复杂的逻辑。

后端代码

为了优化 Spring Boot 后端代码以更好地支持文件分片上传和断点续传,我们可以考虑以下几个方面:

  1. 增加断点续传支持:提供一个接口来检查特定文件的已上传分片。
  2. 优化文件存储:使用更高效的方式来存储和访问分片。
  3. 增强错误处理:确保在读写操作中适当处理异常。
  4. 验证分片完整性:在接收到分片时验证其完整性,如校验分片大小或内容。
  5. 日志记录:记录重要操作,帮助调试和监控上传过程。

示例代码

这是一个优化后的 Spring Boot 控制器实现示例:

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.BitSet;

@RestController
@RequestMapping("/file")
public class FileUploadController {

    private final String UPLOAD_DIR = "/path/to/upload/dir/";

    @PostMapping("/upload")
    public ResponseEntity<String> uploadFileChunk(
            @RequestParam("file") MultipartFile file,
            @RequestParam("chunkNumber") int chunkNumber,
            @RequestParam("totalChunks") int totalChunks,
            @RequestParam("fileId") String fileId) {

        try {
            Path chunkFile = Paths.get(UPLOAD_DIR + fileId + "_" + chunkNumber);
            Files.write(chunkFile, file.getBytes());

            return ResponseEntity.ok("Chunk uploaded successfully");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body("Error uploading chunk");
        }
    }

    @GetMapping("/checkUploadedChunks")
    public ResponseEntity<BitSet> checkUploadedChunks(@RequestParam("fileId") String fileId,
                                                      @RequestParam("totalChunks") int totalChunks) {
        BitSet uploadedChunks = new BitSet(totalChunks);
        for (int i = 1; i <= totalChunks; i++) {
            if (Files.exists(Paths.get(UPLOAD_DIR + fileId + "_" + i))) {
                uploadedChunks.set(i - 1);
            }
        }
        return ResponseEntity.ok(uploadedChunks);
    }

    @PostMapping("/mergeChunks")
    public ResponseEntity<String> mergeChunks(@RequestParam("fileId") String fileId,
                                              @RequestParam("totalChunks") int totalChunks) {
        try {
            mergeFileChunks(fileId, totalChunks);
            return ResponseEntity.ok("File merged successfully");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body("Error merging chunks");
        }
    }

    private void mergeFileChunks(String fileId, int totalChunks) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(UPLOAD_DIR + fileId);
             BufferedOutputStream mergingStream = new BufferedOutputStream(fos)) {
            for (int i = 1; i <= totalChunks; i++) {
                Path chunkFile = Paths.get(UPLOAD_DIR + fileId + "_" + i);
                Files.copy(chunkFile, mergingStream);
                Files.delete(chunkFile);
            }
        }
    }
}

优化点说明

  • 断点续传接口checkUploadedChunks 接口允许客户端查询特定文件的已上传分片。
  • 分片合并接口mergeChunks 接口用于合并所有上传的分片。
  • 错误处理和日志记录:在关键操作中加入了异常捕获和日志记录。

这些优化有助于提高后端处理的效率和可靠性,并支持更复杂的上传场景。根据实际需求,可以进一步增加如上传权限检查、分片完整性校验等功能。


标签:chunkNumber,断点,分片,虚传,file,totalChunks,上传,fileId
From: https://blog.51cto.com/u_13171517/8768519

相关文章

  • vue实现大文件分片上传
    这里使用了elementui的文件上传插件<divclass="inputTitle">人员资料</div><divclass="uploadBox"><divclass="picture"><imgsrc="@/assets/images/zip-before.png">......
  • vue实现大文件分片上传 vue-simple-uploader
    首先为什么要分片上传?大部分小白使用element-ui中上传组件,但是直接用它上传大文件会超时或者RequestEntityTooLarge(请求实体太大)这种问题。1.使用插件vue-simple-uploader我的这个可以自定义样式(没懂的留言给我)1.1customUploader封装组件上代码:<template><divid="......
  • Vue前端+后端实现带进度条文件分片上传
    传输参数对象packagecom.deju.provider.upload.domain;importlombok.Data;importorg.springframework.web.multipart.MultipartFile;@DatapublicclassMultipartFileParam{ //文件传输任务ID privateStringtaskId; //当前为第几分片 privateintchun......
  • dom断点可定位react组件值修改
    react组件的值修改,也可以使用dom断点来定位。之前一直误区,认为react组件的修改,不能用dom断点来拦截,实际上在涉及到修改具体原生组件属性的时候,也可定位。例如:react组件内部使用了input组件,react组件值变化导致input的value发生改变,使用dom断点就可定位。由于input组件的属性修......
  • StackGres 数据库平台工程,使用 Citus + Patroni 创建生产级高可用分布式 PostgreSQL
    系列StackGres,可私有部署的云原生数据库平台工程StackGres 数据库平台工程功能介绍与快速上手StackGres1.6数据库平台工程集群配置管理(K8SPods/PostgreSQL/PgBouncer)StackGres1.6数据库平台工程,集群高可用(Patroni3管理)什么是ShardedCluster(分片集群)Sha......
  • 使用 PyTorch 完全分片数据并行技术加速大模型训练
    本文,我们将了解如何基于PyTorch最新的完全分片数据并行(FullyShardedDataParallel,FSDP)功能用Accelerate库来训练大模型。动机......
  • 分片/分区和副本
    slot也有分区的意思;(redis里)这是两个很重要的概念,新的存储中间件如ES、Kafka、MongoDB等都用了这两种技术;分片/分区是实现数据分流的重要手段,也是实现动态扩容的重要手段;而副本则是冗余数据实现高可用而数据具体是放哪个分片则是通过路由来实现,kafka它要求所有的数据都有一个ke......
  • idea远程打断点
    某些情况调试必须要在centos环境,本文介绍idea远程断点调试方法。请确保有一台自用服务器,可以按照本文开启远程断点。tomcat配置找到tomcat配置文件./bin/catalina.sh,增加下面一行命令CATALINA_OPTS="-Xdebug-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"此处使......
  • Vue3 + Express 实现大文件分片上传、断点续传、秒传
    前言在日常开发中,文件上传是常见的操作之一。文件上传技术使得用户可以方便地将本地文件上传到Web服务器上,这在许多场景下都是必需的,比如网盘上传、头像上传等。但是当需要上传比较大的文件的时候,容易碰到以下问题:上传时间比较久;中间一旦出错就需要重新上传;一般服务端会对......
  • 关于es中集群,节点,分片和副本的理解
    集群页面中每一个对象就是一个集群节点集群中包含许多es实例,其中一个es实例就是一个节点节点也分许多功能分片和副本该例子中分片数为9,副本数为1数据节点就是Node注意:a和b是同样的数据,a为主分片,b为副本分片,但是同样的数据不能放在相同的节点上面(比如a1和b1不能),......