更新時間:2022-08-23 11:20:30 來源:動力節點 瀏覽1896次
Java斷點續傳的原理是什么?動力節點小編來告訴大家。
“斷點續傳”最最基礎的原理就是:我們要在下載行為出現中斷的時候,記錄下中斷的位置信息,然后在下次行為中讀取。
有了這個位置信息之后,想想我們該怎么做。很簡單,在新的下載行為開始的時候,直接從記錄的這個位置開始下載內容,而不再從頭開始。
• 當“上傳(下載)的行為”出現中斷,我們需要記錄本次上傳(下載)的位置(position)。
• 當“續”這一行為開始,我們直接跳轉到postion處繼續上傳(下載)的行為。
當“續傳”的行為開始,我們需要需要從上次記錄的position位置開始讀寫操作,所以我們需要一個類似于“指針”功能的東西。
我們當然也可以自己想辦法去實現這樣一個“指針”,但高興地是,Java已經為我們提供了這樣的一個類,那就是RandomAccessFile。
這個類的功能從名字就很直觀的體現了,能夠隨機的去訪問文件。
我們看一下API文檔中對該類的說明:
此類的實例支持對隨機訪問文件的讀取和寫入。隨機訪問文件的行為類似存儲在文件系統中的一個大型 byte 數組。
如果隨機訪問文件以讀取/寫入模式創建,則輸出操作也可用;輸出操作從文件指針開始寫入字節,并隨著對字節的寫入而前移此文件指針。
寫入隱含數組的當前末尾之后的輸出操作導致該數組擴展。該文件指針可以通過 getFilePointer 方法讀取,并通過 seek 方法設置。
為了通過對比加深理解,我們先來寫一段正常的代碼,即正常讀寫,不發生中斷:
public class Test {
public static void main(String[] args) {
// 源文件與目標文件
File sourceFile = new File("D:/", "test.txt");
File targetFile = new File("E:/", "test.txt");
// 輸入輸出流
FileInputStream fis = null;
FileOutputStream fos = null;
// 數據緩沖區
byte[] buf = new byte[1];
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(targetFile);
// 數據讀寫
while (fis.read(buf) != -1) {
System.out.println("write data...");
fos.write(buf);
}
} catch (FileNotFoundException e) {
System.out.println("指定文件不存在");
} catch (IOException e) {
// TODO: handle exception
} finally {
try {
// 關閉輸入輸出流
if (fis != null)
fis.close();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
該段代碼運行,我們就會發現在E盤中已經成功拷貝了一份“test.txt”。這段代碼很簡單,唯一稍微說一下就是:
我們看到我們將buf,即緩沖區 設置的大小是1,這其實就代表我們每次read,是讀取一個字節的數據(即1個英文字母)。
現在,我們就來模擬這個讀寫中斷的行為,我們將之前的代碼完善如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
public class Test {
private static int position = -1;
public static void main(String[] args) {
// 源文件與目標文件
File sourceFile = new File("D:/", "test.txt");
File targetFile = new File("E:/", "test.txt");
// 輸入輸出流
FileInputStream fis = null;
FileOutputStream fos = null;
// 數據緩沖區
byte[] buf = new byte[1];
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(targetFile);
// 數據讀寫
while (fis.read(buf) != -1) {
fos.write(buf);
// 當已經上傳了3字節的文件內容時,網絡中斷了,拋出異常
if (targetFile.length() == 3) {
position = 3;
throw new FileAccessException();
}
}
} catch (FileAccessException e) {
keepGoing(sourceFile,targetFile, position);
} catch (FileNotFoundException e) {
System.out.println("指定文件不存在");
} catch (IOException e) {
// TODO: handle exception
} finally {
try {
// 關閉輸入輸出流
if (fis != null)
fis.close();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void keepGoing(File source,File target, int position) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
RandomAccessFile readFile = new RandomAccessFile(source, "rw");
RandomAccessFile writeFile = new RandomAccessFile(target, "rw");
readFile.seek(position);
writeFile.seek(position);
// 數據緩沖區
byte[] buf = new byte[1];
// 數據讀寫
while (readFile.read(buf) != -1) {
writeFile.write(buf);
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class FileAccessException extends Exception {
}
在這次改動當中都做了什么工作:
• 首先,我們定義了一個變量position,記錄在發生中斷的時候,已完成讀寫的位置。(這是為了方便,實際來說肯定應該講這個值存到文件或者數據庫等進行持久化)
• 然后在文件讀寫的while循環中,我們去模擬一個中斷行為的發生。這里是當targetFile的文件長度為3個字節則模擬拋出一個我們自定義的異常。(我們可以想象為實際下載中,已經上傳(下載)了”x”個字節的內容,這個時候網絡中斷了,那么我們就在網絡中斷拋出的異常中將”x”記錄下來)。
• 剩下的就如果我們之前說的一樣,在“續傳”行為開始后,通過RandomAccessFile類來包裝我們的文件,然后通過seek將指針指定到之前發生中斷的位置進行讀寫就搞定了。
(實際的文件下載上傳,我們當然需要將保存的中斷值上傳給服務器,這個方式通常為httpConnection.setRequestProperty(“RANGE”,”bytes=x”);)
在我們這段代碼,開啟”續傳“行為,即keepGoing方法中:我們起頭讓線程休眠10秒鐘,這正是為了讓我們運行程序看到效果。
現在我們運行程序,那么文件就會開啟“由D盤上傳到E盤的過程”,我們首先點開E盤,會發現的確多了一個test.txt文件,打開它發現內容如下只有"abc"
沒錯,這個時候我們發現內容只有“abc”。這是在我們預料以內的,因為我們的程序模擬在文件上傳了3個字節的時候發生了中斷。
Ok,我們靜靜的等待10秒鐘過去,然后再點開該文件,看看是否能夠成功:
我們發現內容的確已經變成了“abcdef”,由此也就完成了續傳。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習