文件分片上传功能

  1. 后端代码示例
    import org.springframework.web.bind.annotation.;
    import org.springframework.web.multipart.MultipartFile;
    import java.io.
    ;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;

@RestController
@RequestMapping(“/upload”)
public class FileUploadController {

// 保存到本项目路径下
private static final String UPLOAD_DIR = "uploads/";

/**
 * 分片上传
 * @param file 分片文件
 * @param filename 文件分片前的名称
 * @param chunkIndex 第几个分片
 * @return
 * @throws IOException
 */
@PostMapping("/chunk")
public String uploadChunk(@RequestParam("file") MultipartFile file,
                          @RequestParam("filename") String filename,
                          @RequestParam("chunkIndex") int chunkIndex) throws IOException {
    File dir = new File(UPLOAD_DIR);
    if (!dir.exists()) {
        dir.mkdirs();
    }

    // 保存每个分片
    File chunkFile = new File(dir, filename + ".part" + chunkIndex);
    Path partPath = Paths.get(chunkFile.getPath());

    // 保存分片到磁盘
    try (InputStream inputStream = file.getInputStream();
         OutputStream outputStream = new FileOutputStream(partPath.toFile())) {
        byte[] buffer = new byte[1024];
        int bytesRead;
        while ((bytesRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, bytesRead);
        }
    }

    return "分片 " + chunkIndex + " 上传完毕.";

}

/**
 * 合并分片
 * @param filename 文件分片前的名称
 * @param totalChunks 文件分片总数
 * @return
 * @throws IOException
 */
@PostMapping("/merge")
public String mergeChunks(@RequestParam("filename") String filename,
                          @RequestParam("totalChunks") int totalChunks) throws IOException {
    File finalFile = new File(UPLOAD_DIR, filename+".zip");
    try (FileOutputStream outputStream = new FileOutputStream(finalFile, true)) {
        for (int i = 0; i < totalChunks; i++) {
            File chunkFile = new File(UPLOAD_DIR, filename + ".part" + i);
            if (chunkFile.exists()) {
                FileInputStream inputStream = new FileInputStream(chunkFile);
                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                inputStream.close();
                // 删除已合并的分片
                chunkFile.delete();
            }
        }
    }

    return "文件合并成功.";
}


@PostMapping("/chunkFile")
public ResponseEntity<String> uploadFile(@RequestParam("file") MultipartFile file) {
    try {

        File dir = new File(UPLOAD_DIR);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        // 获取文件名
        String fileName = file.getOriginalFilename();
        File destFile = new File(UPLOAD_DIR, fileName);

        // 临时保存整个文件
        Path partPath = Paths.get(destFile.getPath());

        // 保存分片到磁盘
        try (InputStream inputStream = file.getInputStream();
             OutputStream outputStream = new FileOutputStream(partPath.toFile())) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }

        // 调用分片保存的方法
        saveFileInChunks(destFile);
        // 删除上传的文件,也可以不删除
        destFile.delete();
        return ResponseEntity.ok("文件已成功上传并分块保存.");
    } catch (IOException e) {
        e.printStackTrace();
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("文件上传失败.");
    }
}

/**
 * 分片保存
 * 按照chunkSize 配置分片
 * @param file
 * @throws IOException
 */
private void saveFileInChunks(File file) throws IOException {
    int chunkSize = 1024 * 1024; // 1MB

    try (InputStream inputStream = new FileInputStream(file)) {
        byte[] buffer = new byte[chunkSize];
        int bytesRead;
        int chunkNumber = 0;

        while ((bytesRead = inputStream.read(buffer)) != -1) {
            File chunkFile = new File(UPLOAD_DIR, file.getName().split("\\.")[0]+".part"+chunkNumber++);
            try (FileOutputStream outputStream = new FileOutputStream(chunkFile)) {
                outputStream.write(buffer, 0, bytesRead);
            }
        }
    }
}

}

  1. 前端代码示例
    使用 JavaScript 实现文件的分片上传逻辑。下面是一个简单的 HTML 页面,允许用户选择文件并上传。
File Upload Upload
<script>  
    document.getElementById('uploadButton').onclick = async () => {  
        const fileInput = document.getElementById('fileInput');  
        const file = fileInput.files[0];  

        if (!file) {  
            alert("Please select a file to upload.");  
            return;  
        }  

        const chunkSize = 1024 * 1024; // 1MB per chunk  
        const totalChunks = Math.ceil(file.size / chunkSize);  

        for (let i = 0; i < totalChunks; i++) {  
            const start = i * chunkSize;  
            const end = Math.min(start + chunkSize, file.size);  
            const chunk = file.slice(start, end);  

            const formData = new FormData();  
            formData.append('file', chunk);  
            formData.append('filename', file.name);  
            formData.append('chunkIndex', i);  

            await fetch('/upload/chunk', {  
                method: 'POST',  
                body: formData,  
            });  
        }  

        // 所有分片上传完成后,进行合并  
        await fetch('/upload/merge', {  
            method: 'POST',  
            headers: {  
                'Content-Type': 'application/x-www-form-urlencoded'  
            },  
            body: new URLSearchParams({  
                'filename': file.name,  
                'totalChunks': totalChunks  
            })  
        });  

        alert('Upload completed and file merged successfully!');  
    };  
</script>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值