实现大文件的分片上传、断点续传功能需要前后端的配合。以下是一个简单的示例,展示如何使用Java和Spring Boot实现大文件的分片上传、断点续传功能。
- 后端 - 使用Spring Boot
首先,确保你的Spring Boot项目已经添加了spring-web的依赖。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
FileUploadController.java
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.stream.StreamSupport;
@RestController
public class FileUploadController {
private static final String UPLOAD_DIR = "uploads/";
private static final int CHUNK_SIZE = 1024 * 1024; // 1MB
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file,
@RequestParam("chunk") int chunk,
@RequestParam("chunks") int chunks) throws Exception {
Path targetFile = Paths.get(UPLOAD_DIR + file.getOriginalFilename());
byte[] buffer = new byte[CHUNK_SIZE];
long startByte = chunk * CHUNK_SIZE;
try (InputStream is = new ByteArrayInputStream(file.getBytes());
RandomAccessFile raf = new RandomAccessFile(targetFile.toFile(), "rw")) {
raf.seek(startByte);
StreamUtils.copy(is, raf, buffer);
}
return "Chunk " + chunk + " uploaded successfully.";
}
@GetMapping("/merge")
public String mergeFile(@RequestParam("fileName") String fileName, @RequestParam("chunkCount") int chunkCount) throws Exception {
Path targetFile = Paths.get(UPLOAD_DIR + fileName);
try (RandomAccessFile raf = new RandomAccessFile(targetFile.toFile(), "rw")) {
for (int i = 0; i < chunkCount; i++) {
byte[] buffer = new byte[CHUNK_SIZE];
raf.seek(i * CHUNK_SIZE);
raf.write(buffer);
}
}
return "File merged successfully.";
}
}
- 前端 - 使用HTML5和JavaScript
在前端,你可以使用HTML5的<input type="file">来选择一个文件,并使用JavaScript将其分片并上传到服务器。这里只是一个简单的示例,真实的应用中你可能需要添加更多的功能,如进度条、错误处理等。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>大文件分片上传示例</title>
</head>
<body>
<input type="file" id="fileInput">
<button onclick="uploadFile()">Upload</button>
<script src="app.js"></script>
</body>
</html>
app.js
户体
function uploadFile() {
let fileInput = document.getElementById('fileInput');
let file = fileInput.files[0];
let chunkSize = 1024 * 1024; // 1MB
let chunks = Math.ceil(file.size / chunkSize);
let currentChunk = 0;
let formData = new FormData();
formData.append('fileName', file.name);
formData.append('chunkCount', chunks);
fetch('/merge', { method: 'POST', body: formData }) // 先通知后端文件总片数,以便后端准备合并文件
.then(() => {
function sendNext() {
let blob = file.slice(currentChunk * chunkSize, (currentChunk + 1) * chunkSize);
formData = new FormData();
formData.append('file', blob);
formData.append('chunk', currentChunk);
formData.append('chunks', chunks);
fetch('/upload', { method: 'POST', body: formData }) // 上传当前分片至服务器,成功后发送下一分片。若失败,可从断点续传。具体逻辑根据需求自行实现。然后递归调用自身,实现分片上传功能。当currentChunk等于chunks时,说明所有分片已经上传完毕。此时可以通知后端进行文件合并操作。
}).then(()=>{
currentChunk++;
if(currentChunk<chunks){sendNext()}
})catch((error)=>{console.log(error)});
uploadFile()函数是整个文件上传的入口函数,首先获取到用户选择的文件,并计算出文件的总片数和每片的大小。然后调用sendNext()函数开始上传文件的第一个分片。sendNext()函数中,使用fetch API向后端发送POST请求,上传当前分片,并携带当前分片的索引和总片数信息。
后端在接收到分片后,将分片写入到对应的文件中,并返回成功响应。前端在接收到成功响应后,递归调用sendNext()函数,上传下一个分片,直到所有分片上传完毕。此时可以通知后端进行文件合并操作。后端在接收到合并请求后,将所有分片按照顺序合并成一个完整的文件,并返回成功响应。前端在接收到成功响应后,提示用户文件上传成功。注意:上述代码只是一个简单的示例,真实的应用中你需要处理更多的边界情况和错误情况,如网络中断、文件不存在等。同时,你还需要考虑如何保证上传的文件的安全性和隐私性。
上述代码提供了一个大文件分片上传和断点续传的基本框架。但请注意,实际生产环境中需要考虑更多的细节和异常情况。此外,为了提高用户体验和上传效率,你可能还需要添加进度条、并行上传、重试机制等功能。