测试大文件分块和合并以及大文件上传报错MaxUploadSizeExceededException

文件分块的流程

  1. 获取源文件长度
  2. 根据设定的分块文件大小,计算出块数(向上取整,例如33.4M的文件,块大小为1M,则需要34块)
  3. 从源文件读取数据,并依次向每一个块文件写数据

文件分块测试代码如下

/**
    * 分块测试
    */
   @Test
   void testChunk() throws IOException {
       //源文件
       File file = new File("C:\\Users\\thirty\\Videos\\Captures\\1.mp4");
       //分块存储路径
       String chunkFilePath = "D:\\video\\chunk\\";
       //分块文件的大小
       int chunkSize = 1024 * 1024;
       //分块文件个数
       int chunkNum = Math.toIntExact(file.length() / chunkSize);
       if (file.length() % chunkSize != 0) {
           chunkNum += 1;
       }
       // 缓冲区大小
       byte[] bytes = new byte[1024];
       // 使用RandomAccessFile访问文件
       RandomAccessFile file_r = new RandomAccessFile(file, "r");
       // 遍历分块,依次向每一个分块写入数据
       for (int i = 0; i < chunkNum; i++) {
           // 创建分块文件,默认文件名 path + i,例如chunk1  chunk2
           File chunkFile = new File(chunkFilePath + i);
           //分块文件写入流
           RandomAccessFile file_rw = new RandomAccessFile(chunkFile, "rw");
           int len = -1;
           // 向分块文件写入数据
           while ((len = file_r.read(bytes)) != -1) {
               file_rw.write(bytes, 0, len);
               // 写满就停
               if (chunkFile.length() >= chunkSize) {
                   break;
               }
           }
       }
       file_r.close();
       System.out.println("写入分块文件完毕");
   }

文件合并流程

  1. 找到要合并的文件并按文件分块的先后顺序排序
  2. 创建合并文件
  3. 依次从合并的文件中读取数据冰箱合并文件写入数据
  • 文件合并的测试代码
void testMerge() throws IOException {
       // 块文件目录
       File chunkFolder = new File("D:\\video\\chunk\\");
       // 源文件
       File sourceFile = new File("C:\\Users\\thirty\\Videos\\Captures\\1.mp4");

       // 文件名升序排序
       File[] files = chunkFolder.listFiles();
       List<File> fileList = Arrays.asList(files);
       // 合并文件
       File mergeFile = new File("D:\\video\\chunk\\1.mp4");
       Collections.sort(fileList, Comparator.comparingInt(o -> Integer.parseInt(o.getName())));
       // 用于写文件
       RandomAccessFile raf_write = new RandomAccessFile(mergeFile, "rw");
       // 缓冲区
       byte[] buffer = new byte[1024];
       // 合并文件
       for (File chunkFile : fileList) {
           RandomAccessFile raf_read = new RandomAccessFile(chunkFile, "r");
           int len;
           while ((len = raf_read.read(buffer)) != -1) {
               raf_write.write(buffer, 0, len);
           }
           raf_read.close();
       }
       raf_write.close();
       // 判断合并后的文件是否与源文件相同
       FileInputStream fileInputStream = new FileInputStream(sourceFile);
       FileInputStream mergeFileStream = new FileInputStream(mergeFile);
       //取出原始文件的md5
       String originalMd5 = DigestUtils.md5Hex(fileInputStream);
       //取出合并文件的md5进行比较
       String mergeFileMd5 = DigestUtils.md5Hex(mergeFileStream);
       if (originalMd5.equals(mergeFileMd5)) {
           System.out.println("合并文件成功");
       } else {
           System.out.println("合并文件失败");
       }
   }

文件超 1M 但小于 10M 时的异常信息:

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

文件超 10M 的异常信息:

Resolved [org.springframework.web.multipart.MaxUploadSizeExceededException: Maximum upload size exceeded; nested exception is java.lang.IllegalStateException: org.apache.tomcat.util.http.fileupload.FileUploadBase$SizeLimitExceededException: the request was rejected because its size (12209424) exceeds the configured maximum (10485760)]

解决方案,在yml文件中增加配置

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

server:
  tomcat:
    max-swallow-size: -1

注意上面最重要的是要配置内嵌的 tomcat 的最大吞吐量即 max-swallow-size,可以设置 -1 不限制,也可以设置一下比较大的数字。当上传文件超 tomcat 的大小限制后会先于 Controller 触发异常,所以这时异常处理类无法捕获 Controller 层的异常。

这样当上传文件超大小限制后就可以被全局异常处理类捕获了。

posted @ 2023-07-11 11:29  duanthirty  阅读(48)  评论(0)    收藏  举报