大文件切片上传服务器

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package io.github.lyr2000.dissertation.controller.test;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Profile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;

/**
 * @author lyr
 * @description fileTest
 * @create 2021-11-18 23:44
 */
@Slf4j
@RestController
@RequestMapping("/test/api/file")
@Profile("test")
public class FileTestController {
    //系统资源存储位置
    @Value("D:/ASUS/Desktop/app/")
    private String FILE_DIR;

    @PostConstruct
    void init() {
        log.info("test 文件上传测试开启,本地测试路径: = {}", FILE_DIR);
    }


    @PostMapping("/upload")
    public String upload(@RequestPart("file") MultipartFile file) {
        String originName = file.getOriginalFilename();
        String destPath = FILE_DIR + '/' + originName;
        File dest = new File(destPath);
        try {
            file.transferTo(dest);
            return "上传成功";
        } catch (Exception e) {
            log.error("upload error = {}", e.getMessage());
        }
        return "上传失败!!!!";

    }

    //合并所有索引文件,生成最终文件
    private void mergeFiles(String originName, int totalCnt) throws Exception {
        if (totalCnt <= 0 || StrUtil.isBlank(originName)) {
            return;
        }
        // List<String> list = new ArrayList<>(totalCnt);
        File dest = new File(FILE_DIR + '/' + originName);
        //第二个参数设置为 true,就是追加上传
        FileOutputStream destOs = new FileOutputStream(dest, true);

        byte[] buf = new byte[1024 * 1024];
        int len = 0;
        try {
            for (int i = 1; i <= totalCnt; i++) {
                String tempFileName = String.format("%s/%s-no-%d",FILE_DIR, originName, i);
                FileInputStream inputStream = new FileInputStream(new File(tempFileName));
                while ((len = inputStream.read(buf)) != -1) {
                    destOs.write(buf, 0, len);
                }
                inputStream.close();

            }
        } catch (Exception e) {
            log.error("msg = {}", e.getMessage());
        } finally {
            //合并文件 完成
            destOs.close();
        }


        //删除临时索引文件
        for (int i = 1; i <= totalCnt; i++) {
            String tempFileName = String.format("%s/%s-no-%d",FILE_DIR, originName, i);
            boolean res = new File(tempFileName).delete();
            if (!res) {
                log.warn("删除临时文件失败 = {}", tempFileName);
            }
        }

    }

    @PostMapping("/upload2")
    public String upload2(
            @RequestPart("file") MultipartFile file,
            @RequestParam("targetName") String targetName,
            @RequestParam("seq") Integer seq,
            @RequestParam("total") Integer total

    ) {
        String originName = file.getOriginalFilename();
        String destPath = FILE_DIR + '/' + originName;
        File dest = new File(destPath);
        try {
            file.transferTo(dest);
            log.info("upload2 ok ,seq={}, filename = {}", seq, originName);
            if (seq != null && seq.equals(total)) {
                // 如果 seq == total
                //上传完最后一个文件了,再合并文件
                mergeFiles(targetName, total);
            }
            return "上传成功";
        } catch (Exception e) {
            log.error("upload error = {}", e.getMessage());
        }
        return "上传失败!!!!";

    }


}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
  </head>
  <body>
    <form method="POST" enctype="multipart/form-data">
      上传文件:
      <input
        multiple
        id="file"
        type="file"
        name="file"
        placeholder="上传文件"
      />
      <button id="upload" type="button">上传</button>
    </form>
    <script>
      $("#upload").click(() => {
        upload();
      });
    </script>

    <script>
      //设置每个切片大小 , 2M
      let bytesPerPiece = 1024 * 1024 * 2;

      //上传文件函数
      function upload() {
        //获取上传文件
        let file = document.getElementById("file").files[0];
        console.log(file);
        let start = 0,
          end,
          index = 0,
          filesize = file.size,
          name = file.name;
        //计算切片总数
        let totalPieces = Math.ceil(filesize / bytesPerPiece);
        console.log('total pieces = ',totalPieces)
        let ucnt = 0; //用于记录第几个数据包
        while (ucnt < totalPieces) {
          end = start + bytesPerPiece;
          if (end > filesize) {
            end = filesize;
          }
          let chunk = file.slice(start, end);
          let formData = new FormData();
          ucnt++;
          let filename = `${name}-no-${ucnt}`;
          formData.append("file", chunk, filename);
          //seq 表示 第几个数据包
          formData.append("seq", ucnt);
          //提交总分片数量
          formData.append("total",totalPieces);

          //最终名字
          formData.append("targetName",name);
          //原生js发请求
          //   let xhr = new XMLHttpRequest();
          //   xhr.onreadystatechange = function(){
          //       if(this.readyState == 4 && this.status == 200){

          //       }
          //   }
          //   xhr.open('post', '/api/upload', true);
          //   xhr.send(formData);
          // 使用jquery,需要将contentType,processData设置为false

          console.log("upload --", formData, ucnt);
          $.ajax({
            url: "/test/api/file/upload2",
            type: "post",
            data: formData,
            processData: false,
            contentType: false,
            async: false,
          })
          .success((res) => {
            console.log("ok .. {}", res);
            
          })
          .error((err) => {});
          start = end + 1

        }
      }
    </script>
  </body>
</html>