大文件分片上传java前后端代码
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>大文件分片上传</title>
</head>
<body>
<div>
<h3>选择文件</h3>
<input type="file" id="fileInput" />
<br />
<br />
<h3>上传进度</h3>
<progress id="progressBar" value="0" max="100"></progress>
<br />
<br />
<button onclick="startUpload()">开始上传</button>
</div>
<script>
// 上传文件的起始位置
var start = 0;
// 分片大小(5MB)
var chunkSize = 5 * 1024 * 1024;
// 上传文件的总大小
var fileSize = 0;
// 上传文件的分片总数
var totalChunks = 0;
// 当前上传的分片
var currentChunk = 0;
// 文件对象
var file = null;
// 上传文件的唯一标识符
var uploadId = null;
// 选择文件
var fileInput = document.getElementById("fileInput");
fileInput.addEventListener("change", function (event) {
file = event.target.files[0];
fileSize = file.size;
totalChunks = Math.ceil(fileSize / chunkSize);
console.log("文件大小:" + fileSize);
console.log("分片总数:" + totalChunks);
});
function startUpload() {
// 发送请求,获取上传文件的唯一标识符
var xhr = new XMLHttpRequest();
xhr.open("GET", "/getUploadId?fileName=" + file.name + "&fileSize=" + fileSize);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
uploadId = xhr.responseText;
console.log("上传文件的唯一标识符:" + uploadId);
// 开始上传文件的第一个分片
uploadChunk();
}
};
xhr.send();
}
function uploadChunk() {
// 计算当前分片的起始位置和结束位置
var chunkStart = start + currentChunk * chunkSize;
var chunkEnd = Math.min(chunkStart + chunkSize, fileSize);
var chunk = file.slice(chunkStart, chunkEnd);
// 发送分片上传请求
var xhr = new XMLHttpRequest();
xhr.open("POST", "/uploadChunk");
xhr.setRequestHeader("Content-Type", "application/octet-stream");
xhr.setRequestHeader("X-Upload-Id", uploadId);
xhr.setRequestHeader("X-Chunk-Number", currentChunk + 1);
xhr.setRequestHeader("X-Total-Chunks", totalChunks);
xhr.setRequestHeader("X-Chunk-Size", chunkSize);
xhr.setRequestHeader("X-File-Name", file.name);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log("上传分片成功:" + xhr.responseText);
// 更新上传进度
var progress = Math.round((chunkEnd / fileSize) * 100);
document.getElementById("progressBar").value = progress;
// 如果还有下一个分片,则继续上传
if (currentChunk + 1 < totalChunks) {
currentChunk++;
uploadChunk();
}
}
};
xhr.send(chunk);
}
</script>
</body>
</html>
后端代码:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class FileUploadServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 存储上传文件的目录
private static final String UPLOAD_DIR = "uploads/";
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取上传文件的唯一标识符
String fileName = request.getParameter("fileName");
long fileSize = Long.parseLong(request.getParameter("fileSize"));
String uploadId = UUID.randomUUID().toString();
// 创建分片上传记录文件
Path path = Paths.get(UPLOAD_DIR + fileName + "." + uploadId);
Files.createFile(path);
// 返回分片上传记录文件的唯一标识符
response.getWriter().write(uploadId);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// 获取上传文件的唯一标识符、分片编号、分片总数、分片大小、文件名
String uploadId = request.getHeader("X-Upload-Id");
int chunkNumber = Integer.parseInt(request.getHeader("X-Chunk-Number"));
int totalChunks = Integer.parseInt(request.getHeader("X-Total-Chunks"));
int chunkSize = Integer.parseInt(request.getHeader("X-Chunk-Size"));
String fileName = request.getHeader("X-File-Name");
// 获取上传文件的分片
InputStream inputStream = request.getInputStream();
byte[] chunk = inputStream.readAllBytes();
// 将上传文件的分片写入临时文件
Path path = Paths.get(UPLOAD_DIR + fileName + "." + uploadId);
try (OutputStream outputStream = new FileOutputStream(path.toFile(), true)) {
outputStream.write(chunk);
}
// 如果是最后一个分片,则合并分片为完整的上传文件
if (chunkNumber == totalChunks) {
// 从临时文件读取上传文件的所有分片
byte[] fileBytes = Files.readAllBytes(path);
// 删除临时文件
Files.delete(path);
// 创建上传文件的目录(如果不存在)
Path uploadPath = Paths.get(UPLOAD_DIR);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// 写入完整的上传文件
Path filePath = Paths.get(UPLOAD_DIR + fileName);
Files.write(filePath, fileBytes);
// 返回上传成功信息
response.getWriter().write("上传成功");
} else {
// 返回上传分片成功信息
response.getWriter().write("上传分片成功");
}
}
}
说明:
- 前端代码通过文件选择框选择要上传的文件,然后将文件分成多个分片上传,每个分片大小为5MB。
- 前端代码通过XMLHttpRequest对象发送GET请求,获取上传文件的唯一标识符。然后通过XMLHttpRequest对象发送POST请求,上传文件的每个分片。
- 后端代码根据文件名、文件大小和随机生成的UUID创建一个分片上传记录文件,文件名格式为
<文件名>.<上传文件的唯一标识符>。每次上传分片时,将分片写入分片上传记录文件。如果是最后一个分片,则将所有分片合并成完整的上传文件,并将上传文件存储到uploads/目录下。 - 上传文件的唯一标识符、分片编号、分片总数、分片大小和文件名通过HTTP请求头传递
原文地址: http://www.cveoy.top/t/topic/egka 著作权归作者所有。请勿转载和采集!