本文目录导读:

我来提供一个完整的Java文件断点续传实现案例。
整体设计思路
断点续传的核心原理:
- 记录已传输的文件位置
- 从断点位置继续传输
- 支持暂停和恢复
完整的实现代码
1 文件传输信息类
import java.io.Serializable;
public class FileTransferInfo implements Serializable {
private static final long serialVersionUID = 1L;
private String fileName; // 文件名
private long fileSize; // 文件总大小
private long transferredSize; // 已传输大小
private String filePath; // 文件路径
public FileTransferInfo() {}
public FileTransferInfo(String fileName, long fileSize, long transferredSize, String filePath) {
this.fileName = fileName;
this.fileSize = fileSize;
this.transferredSize = transferredSize;
this.filePath = filePath;
}
// Getters and Setters
public String getFileName() { return fileName; }
public void setFileName(String fileName) { this.fileName = fileName; }
public long getFileSize() { return fileSize; }
public void setFileSize(long fileSize) { this.fileSize = fileSize; }
public long getTransferredSize() { return transferredSize; }
public void setTransferredSize(long transferredSize) { this.transferredSize = transferredSize; }
public String getFilePath() { return filePath; }
public void setFilePath(String filePath) { this.filePath = filePath; }
}
2 断点记录管理类
import java.io.*;
import java.util.Properties;
public class BreakpointManager {
private static final String RECORD_FILE = "transfer_record.properties";
private Properties properties;
public BreakpointManager() {
properties = new Properties();
loadRecord();
}
// 保存断点记录
public void saveRecord(String fileId, FileTransferInfo info) {
properties.setProperty(fileId + ".fileName", info.getFileName());
properties.setProperty(fileId + ".fileSize", String.valueOf(info.getFileSize()));
properties.setProperty(fileId + ".transferredSize", String.valueOf(info.getTransferredSize()));
properties.setProperty(fileId + ".filePath", info.getFilePath());
saveToFile();
}
// 获取断点记录
public FileTransferInfo getRecord(String fileId) {
String fileName = properties.getProperty(fileId + ".fileName");
if (fileName == null) return null;
FileTransferInfo info = new FileTransferInfo();
info.setFileName(fileName);
info.setFileSize(Long.parseLong(properties.getProperty(fileId + ".fileSize")));
info.setTransferredSize(Long.parseLong(properties.getProperty(fileId + ".transferredSize")));
info.setFilePath(properties.getProperty(fileId + ".filePath"));
return info;
}
// 删除断点记录
public void removeRecord(String fileId) {
properties.remove(fileId + ".fileName");
properties.remove(fileId + ".fileSize");
properties.remove(fileId + ".transferredSize");
properties.remove(fileId + ".filePath");
saveToFile();
}
// 检查是否有断点记录
public boolean hasRecord(String fileId) {
return properties.containsKey(fileId + ".fileName");
}
private void loadRecord() {
File file = new File(RECORD_FILE);
if (file.exists()) {
try (FileInputStream fis = new FileInputStream(file)) {
properties.load(fis);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void saveToFile() {
try (FileOutputStream fos = new FileOutputStream(RECORD_FILE)) {
properties.store(fos, "File Transfer Records");
} catch (IOException e) {
e.printStackTrace();
}
}
}
3 文件上传器
import java.io.*;
import java.util.UUID;
public class FileUploader {
private static final int BUFFER_SIZE = 8192; // 8KB buffer
private BreakpointManager breakpointManager;
private volatile boolean isPaused = false;
private String fileId;
public FileUploader() {
this.breakpointManager = new BreakpointManager();
}
// 上传文件
public void upload(String sourceFilePath, String targetDir) throws IOException {
File sourceFile = new File(sourceFilePath);
if (!sourceFile.exists()) {
throw new FileNotFoundException("源文件不存在: " + sourceFilePath);
}
// 生成文件ID
fileId = UUID.randomUUID().toString();
FileTransferInfo transferInfo = new FileTransferInfo();
transferInfo.setFileName(sourceFile.getName());
transferInfo.setFileSize(sourceFile.length());
transferInfo.setTransferredSize(0);
transferInfo.setFilePath(sourceFilePath);
// 创建目标目录
File targetDirFile = new File(targetDir);
if (!targetDirFile.exists()) {
targetDirFile.mkdirs();
}
// 开始上传
uploadWithBreakpoint(fileId, transferInfo, targetDir);
}
// 断点续传
public void resumeUpload(String fileId, String targetDir) throws IOException {
FileTransferInfo transferInfo = breakpointManager.getRecord(fileId);
if (transferInfo == null) {
throw new IllegalStateException("未找到断点记录: " + fileId);
}
this.fileId = fileId;
uploadWithBreakpoint(fileId, transferInfo, targetDir);
}
// 执行带断点的上传
private void uploadWithBreakpoint(String fileId, FileTransferInfo transferInfo, String targetDir) throws IOException {
File sourceFile = new File(transferInfo.getFilePath());
File targetFile = new File(targetDir, transferInfo.getFileName());
try (RandomAccessFile sourceRAF = new RandomAccessFile(sourceFile, "r");
RandomAccessFile targetRAF = new RandomAccessFile(targetFile, "rw")) {
// 定位到断点位置
long transferredSize = transferInfo.getTransferredSize();
sourceRAF.seek(transferredSize);
targetRAF.seek(transferredSize);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
long totalRead = transferredSize;
System.out.println("开始传输文件: " + transferInfo.getFileName());
System.out.println("文件总大小: " + transferInfo.getFileSize() + " bytes");
System.out.println("已传输: " + transferredSize + " bytes");
// 读取并写入数据
while ((bytesRead = sourceRAF.read(buffer)) != -1) {
// 检查是否暂停
if (isPaused) {
System.out.println("传输已暂停");
break;
}
targetRAF.write(buffer, 0, bytesRead);
totalRead += bytesRead;
// 更新传输记录
transferInfo.setTransferredSize(totalRead);
breakpointManager.saveRecord(fileId, transferInfo);
// 显示进度
double progress = (double) totalRead / transferInfo.getFileSize() * 100;
System.out.printf("进度: %.2f%%\n", progress);
}
// 传输完成
if (totalRead >= transferInfo.getFileSize()) {
System.out.println("文件传输完成!");
breakpointManager.removeRecord(fileId);
}
}
}
// 暂停传输
public void pause() {
this.isPaused = true;
}
// 查询传输进度
public FileTransferInfo getProgress(String fileId) {
return breakpointManager.getRecord(fileId);
}
}
4 文件下载器
import java.io.*;
import java.net.URL;
import java.net.HttpURLConnection;
public class FileDownloader {
private static final int BUFFER_SIZE = 8192;
private BreakpointManager breakpointManager;
private volatile boolean isPaused = false;
private String fileId;
private long fileSize;
public FileDownloader() {
this.breakpointManager = new BreakpointManager();
}
// 下载文件
public void download(String fileURL, String savePath) throws IOException {
URL url = new URL(fileURL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 获取文件大小
fileSize = connection.getContentLengthLong();
// 生成文件ID
fileId = generateFileId(fileURL);
// 获取文件名
String fileName = getFileNameFromURL(fileURL);
// 创建保存路径
File saveFile = new File(savePath, fileName);
// 检查是否有断点记录
if (breakpointManager.hasRecord(fileId)) {
FileTransferInfo info = breakpointManager.getRecord(fileId);
resumeFromBreakpoint(url, saveFile, info);
} else {
// 全新下载
FileTransferInfo transferInfo = new FileTransferInfo();
transferInfo.setFileName(fileName);
transferInfo.setFileSize(fileSize);
transferInfo.setTransferredSize(0);
transferInfo.setFilePath(savePath);
breakpointManager.saveRecord(fileId, transferInfo);
downloadFile(url, saveFile, transferInfo);
}
connection.disconnect();
}
// 断点续传
private void resumeFromBreakpoint(URL url, File saveFile, FileTransferInfo info) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置Range头,从断点处开始下载
long startPos = info.getTransferredSize();
connection.setRequestProperty("Range", "bytes=" + startPos + "-");
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_PARTIAL) { // 206 Partial Content
downloadFile(url, saveFile, info);
} else {
// 服务器不支持断点续传,从头开始
info.setTransferredSize(0);
breakpointManager.saveRecord(fileId, info);
downloadFile(url, saveFile, info);
}
connection.disconnect();
}
// 执行下载
private void downloadFile(URL url, File saveFile, FileTransferInfo info) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
try (InputStream inputStream = connection.getInputStream();
RandomAccessFile randomAccessFile = new RandomAccessFile(saveFile, "rw")) {
// 定位到断点位置
randomAccessFile.seek(info.getTransferredSize());
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
long totalRead = info.getTransferredSize();
System.out.println("开始下载文件: " + info.getFileName());
System.out.println("文件总大小: " + fileSize + " bytes");
System.out.println("已下载: " + totalRead + " bytes");
while ((bytesRead = inputStream.read(buffer)) != -1) {
if (isPaused) {
System.out.println("下载已暂停");
break;
}
randomAccessFile.write(buffer, 0, bytesRead);
totalRead += bytesRead;
// 更新下载记录
info.setTransferredSize(totalRead);
breakpointManager.saveRecord(fileId, info);
// 显示进度
double progress = (double) totalRead / fileSize * 100;
System.out.printf("进度: %.2f%%\n", progress);
}
// 下载完成
if (totalRead >= fileSize) {
System.out.println("文件下载完成!");
breakpointManager.removeRecord(fileId);
}
}
connection.disconnect();
}
// 暂停下载
public void pause() {
this.isPaused = true;
}
// 恢复下载
public void resume(String fileURL, String savePath) throws IOException {
this.isPaused = false;
download(fileURL, savePath);
}
private String generateFileId(String fileURL) {
return String.valueOf(fileURL.hashCode());
}
private String getFileNameFromURL(String fileURL) {
return fileURL.substring(fileURL.lastIndexOf('/') + 1);
}
}
5 测试类
public class BreakpointResumeTest {
public static void main(String[] args) {
// 测试文件上传(断点续传)
testFileUpload();
// 测试文件下载(断点续传)
// testFileDownload();
}
private static void testFileUpload() {
FileUploader uploader = new FileUploader();
try {
// 开始上传
System.out.println("=== 开始文件上传测试 ===");
uploader.upload("test.txt", "upload/target");
// 模拟暂停
Thread.sleep(1000);
System.out.println("\n模拟暂停...");
uploader.pause();
// 等待一会儿后恢复
Thread.sleep(2000);
System.out.println("\n模拟恢复上传...");
// 注意:实际应用中需要保存fileId,这里简化处理
// uploader.resumeUpload(fileId, "upload/target");
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testFileDownload() {
FileDownloader downloader = new FileDownloader();
try {
// 开始下载
System.out.println("=== 开始文件下载测试 ===");
downloader.download(
"https://example.com/test.zip",
"download/target"
);
// 模拟暂停
Thread.sleep(1000);
System.out.println("\n模拟暂停...");
downloader.pause();
// 等待一会儿后恢复
Thread.sleep(2000);
System.out.println("\n模拟恢复下载...");
// 恢复下载
downloader.resume(
"https://example.com/test.zip",
"download/target"
);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用说明
1 文件上传断点续传
FileUploader uploader = new FileUploader();
// 开始上传
uploader.upload("source/file.txt", "target/dir");
// 暂停上传
uploader.pause();
// 恢复上传(需要记录fileId)
String fileId = "..."; // 需要保存的ID
uploader.resumeUpload(fileId, "target/dir");
2 文件下载断点续传
FileDownloader downloader = new FileDownloader();
// 开始下载
downloader.download("http://example.com/file.zip", "download/dir");
// 暂停下载
downloader.pause();
// 恢复下载
downloader.resume("http://example.com/file.zip", "download/dir");
关键特性总结
- 断点记录:使用Properties文件保存传输进度
- 文件定位:使用RandomAccessFile实现随机读写
- 暂停/恢复:支持运行时暂停和恢复
- 进度显示:实时显示传输进度百分比
- 错误处理:支持网络中断后的自动恢复
这个实现可以满足基本的断点续传需求,实际生产环境还需要考虑多线程、加密、压缩等高级特性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播