Java 分片上传实现
1. 流程概述
分片上传是指将一个大文件切分成多个小的片段进行上传,然后在服务器端将这些片段合并成完整的文件。下面是实现分片上传的整个流程:
步骤 | 描述 |
---|---|
1 | 客户端将文件进行分片,生成多个小文件 |
2 | 客户端逐个上传分片文件到服务器 |
3 | 服务器接收并保存分片文件 |
4 | 服务器合并分片文件,生成完整的文件 |
2. 代码实现
客户端代码
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
public class Client {
public static void main(String[] args) {
// 1. 将文件进行分片,生成多个小文件
File file = new File("path/to/largeFile.mp4");
int chunkSize = 1024 * 1024; // 每个分片的大小,这里设定为 1MB
int totalChunks = (int) Math.ceil((double) file.length() / chunkSize);
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
byte[] buffer = new byte[chunkSize];
for (int i = 0; i < totalChunks; i++) {
int bytesRead = raf.read(buffer);
if (bytesRead == -1) {
break;
}
String chunkName = "chunk-" + (i + 1);
// 2. 客户端逐个上传分片文件到服务器
uploadChunk(chunkName, buffer, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void uploadChunk(String chunkName, byte[] data, int bytesRead) {
String endpoint = " // 上传接口的URL
try {
URL url = new URL(endpoint);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/octet-stream");
// 设置请求头,标识当前分片的信息
connection.setRequestProperty("Chunk-Name", chunkName);
connection.setRequestProperty("Content-Length", String.valueOf(bytesRead));
// 通过输出流将分片数据写入请求体
OutputStream outputStream = connection.getOutputStream();
outputStream.write(data, 0, bytesRead);
outputStream.flush();
outputStream.close();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 上传分片成功
System.out.println("Chunk " + chunkName + " uploaded successfully.");
} else {
// 上传分片失败
System.out.println("Failed to upload chunk " + chunkName);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
以上代码实现了客户端的分片上传功能。首先,我们通过 RandomAccessFile
将大文件切分成多个小文件,每个小文件的大小由 chunkSize
决定。然后,逐个调用 uploadChunk
方法将分片文件上传到服务器。
服务器端代码
服务器端需要接收并保存分片文件,并在所有分片文件上传完毕后进行合并。下面是服务器端的代码示例:
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Server extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String chunkName = request.getHeader("Chunk-Name");
int contentLength = Integer.parseInt(request.getHeader("Content-Length"));
// 3. 服务器接收并保存分片文件
saveChunk(chunkName, request.getInputStream(), contentLength);
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().flush();
}
public static void saveChunk(String chunkName, InputStream inputStream, int contentLength) throws IOException {
File saveDirectory = new File("path/to/saveDirectory");
if (!saveDirectory.exists()) {
saveDirectory.mkdirs();
}
File chunkFile = new File(saveDirectory, chunkName);
try (OutputStream outputStream = new FileOutputStream(chunkFile, true)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
}
// 4. 服务器合并分片文件
mergeChunks(saveDirectory);
}
public static void mergeChunks(File saveDirectory) throws IOException {
File[] chunks = saveDirectory.listFiles((dir