斷點續傳的核心思想:記錄已下載的文件位置(斷點),下次下載時從該位置繼續,而非重頭開始。Java 中通過 RandomAccessFile 實現,關鍵方法:
seek(long pos):移動文件指針到指定位置getFilePointer():獲取當前文件指針位置setLength(long len):設置文件長度(預分配空間)package com.dragon.java.downloadfile;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class ResumeDownloadDemo {
public static void main(String[] args) {
File srcFile = new File("D:/Java4Android/01_Java考古學/01_Java考古學.mp4");
File desDir = new File("f:/vidio");
copyFileWithResume(srcFile, desDir);
}
public static void copyFileWithResume(File srcFile, File desDir) {
desDir.mkdirs();
// 配置文件:記錄斷點位置
File configFile = new File(desDir, srcFile.getName().split("\\.")[0] + ".config");
// 目標文件
File desFile = new File(desDir, srcFile.getName());
// 若無配置文件但目標文件存在,視為已下載完成
if (!configFile.exists() && desFile.exists()) {
System.out.println("文件已下載完成!");
return;
}
RandomAccessFile rafSrc = null;
RandomAccessFile rafDes = null;
RandomAccessFile rafConfig = null;
try {
rafSrc = new RandomAccessFile(srcFile, "r");
rafDes = new RandomAccessFile(desFile, "rw");
rafConfig = new RandomAccessFile(configFile, "rw");
// 預分配目標文件空間,避免寫入時擴容開銷
rafDes.setLength(srcFile.length());
// 配置文件固定 8 字節(存一個 long),預防首次讀取 EOF 異常
rafConfig.setLength(8);
// 讀取上次下載位置
long pointer = rafConfig.readLong();
System.out.printf("已下載:%.2f%%%n", (float) pointer / srcFile.length() * 100);
// 移動源/目標文件指針到斷點位置
rafSrc.seek(pointer);
rafDes.seek(pointer);
// 小緩衝區便於觀察斷點續傳效果,生產環境建議 4KB-8KB
byte[] buffer = new byte[32];
int len;
while ((len = rafSrc.read(buffer)) != -1) {
rafDes.write(buffer, 0, len);
// 關鍵:每次寫入後立即記錄最新指針位置
rafConfig.seek(0); // 重置配置文件指針到開頭
rafConfig.writeLong(rafSrc.getFilePointer()); // 記錄最新位置
}
System.out.println("下載成功!");
} catch (IOException e) {
System.out.println("下載中斷:" + e.getMessage());
} finally {
// 安全關閉流
closeQuietly(rafSrc);
closeQuietly(rafDes);
closeQuietly(rafConfig);
// 下載完成後刪除配置文件
if (configFile.exists()) configFile.delete();
}
}
private static void closeQuietly(RandomAccessFile raf) {
if (raf != null) {
try { raf.close(); } catch (IOException ignored) {}
}
}
}
long 類型的斷點位置,每次寫入前 seek(0) 覆蓋舊值,確保隨時可恢復rafDes.setLength(srcFile.length()) 避免寫入過程中頻繁擴容,提升性能finally 區塊確保流關閉,中斷時配置文件已記錄最新進度new byte[8192])這個 Demo 通過本地文件複製模擬了斷點續傳的核心邏輯,網絡下載場景下只需將 rafSrc 替換為 HttpURLConnection 或 OkHttp 的輸入流即可,核心斷點邏輯完全一致。