- 后端代码示例
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);
}
}
}
}
}
- 前端代码示例
使用 JavaScript 实现文件的分片上传逻辑。下面是一个简单的 HTML 页面,允许用户选择文件并上传。
<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>