更新時間:2022-08-23 11:20:30 來源:動力節(jié)點 瀏覽1855次
Java斷點續(xù)傳的原理是什么?動力節(jié)點小編來告訴大家。
“斷點續(xù)傳”最最基礎(chǔ)的原理就是:我們要在下載行為出現(xiàn)中斷的時候,記錄下中斷的位置信息,然后在下次行為中讀取。
有了這個位置信息之后,想想我們該怎么做。很簡單,在新的下載行為開始的時候,直接從記錄的這個位置開始下載內(nèi)容,而不再從頭開始。
• 當(dāng)“上傳(下載)的行為”出現(xiàn)中斷,我們需要記錄本次上傳(下載)的位置(position)。
• 當(dāng)“續(xù)”這一行為開始,我們直接跳轉(zhuǎn)到postion處繼續(xù)上傳(下載)的行為。
當(dāng)“續(xù)傳”的行為開始,我們需要需要從上次記錄的position位置開始讀寫操作,所以我們需要一個類似于“指針”功能的東西。
我們當(dāng)然也可以自己想辦法去實現(xiàn)這樣一個“指針”,但高興地是,Java已經(jīng)為我們提供了這樣的一個類,那就是RandomAccessFile。
這個類的功能從名字就很直觀的體現(xiàn)了,能夠隨機的去訪問文件。
我們看一下API文檔中對該類的說明:
此類的實例支持對隨機訪問文件的讀取和寫入。隨機訪問文件的行為類似存儲在文件系統(tǒng)中的一個大型 byte 數(shù)組。
如果隨機訪問文件以讀取/寫入模式創(chuàng)建,則輸出操作也可用;輸出操作從文件指針開始寫入字節(jié),并隨著對字節(jié)的寫入而前移此文件指針。
寫入隱含數(shù)組的當(dāng)前末尾之后的輸出操作導(dǎo)致該數(shù)組擴展。該文件指針可以通過 getFilePointer 方法讀取,并通過 seek 方法設(shè)置。
為了通過對比加深理解,我們先來寫一段正常的代碼,即正常讀寫,不發(fā)生中斷:
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;
// 數(shù)據(jù)緩沖區(qū)
byte[] buf = new byte[1];
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(targetFile);
// 數(shù)據(jù)讀寫
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 {
// 關(guān)閉輸入輸出流
if (fis != null)
fis.close();
if (fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
該段代碼運行,我們就會發(fā)現(xiàn)在E盤中已經(jīng)成功拷貝了一份“test.txt”。這段代碼很簡單,唯一稍微說一下就是:
我們看到我們將buf,即緩沖區(qū) 設(shè)置的大小是1,這其實就代表我們每次read,是讀取一個字節(jié)的數(shù)據(jù)(即1個英文字母)。
現(xiàn)在,我們就來模擬這個讀寫中斷的行為,我們將之前的代碼完善如下:
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;
// 數(shù)據(jù)緩沖區(qū)
byte[] buf = new byte[1];
try {
fis = new FileInputStream(sourceFile);
fos = new FileOutputStream(targetFile);
// 數(shù)據(jù)讀寫
while (fis.read(buf) != -1) {
fos.write(buf);
// 當(dāng)已經(jīng)上傳了3字節(jié)的文件內(nèi)容時,網(wǎng)絡(luò)中斷了,拋出異常
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 {
// 關(guān)閉輸入輸出流
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);
// 數(shù)據(jù)緩沖區(qū)
byte[] buf = new byte[1];
// 數(shù)據(jù)讀寫
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 {
}
在這次改動當(dāng)中都做了什么工作:
• 首先,我們定義了一個變量position,記錄在發(fā)生中斷的時候,已完成讀寫的位置。(這是為了方便,實際來說肯定應(yīng)該講這個值存到文件或者數(shù)據(jù)庫等進行持久化)
• 然后在文件讀寫的while循環(huán)中,我們?nèi)ツM一個中斷行為的發(fā)生。這里是當(dāng)targetFile的文件長度為3個字節(jié)則模擬拋出一個我們自定義的異常。(我們可以想象為實際下載中,已經(jīng)上傳(下載)了”x”個字節(jié)的內(nèi)容,這個時候網(wǎng)絡(luò)中斷了,那么我們就在網(wǎng)絡(luò)中斷拋出的異常中將”x”記錄下來)。
• 剩下的就如果我們之前說的一樣,在“續(xù)傳”行為開始后,通過RandomAccessFile類來包裝我們的文件,然后通過seek將指針指定到之前發(fā)生中斷的位置進行讀寫就搞定了。
(實際的文件下載上傳,我們當(dāng)然需要將保存的中斷值上傳給服務(wù)器,這個方式通常為httpConnection.setRequestProperty(“RANGE”,”bytes=x”);)
在我們這段代碼,開啟”續(xù)傳“行為,即keepGoing方法中:我們起頭讓線程休眠10秒鐘,這正是為了讓我們運行程序看到效果。
現(xiàn)在我們運行程序,那么文件就會開啟“由D盤上傳到E盤的過程”,我們首先點開E盤,會發(fā)現(xiàn)的確多了一個test.txt文件,打開它發(fā)現(xiàn)內(nèi)容如下只有"abc"
沒錯,這個時候我們發(fā)現(xiàn)內(nèi)容只有“abc”。這是在我們預(yù)料以內(nèi)的,因為我們的程序模擬在文件上傳了3個字節(jié)的時候發(fā)生了中斷。
Ok,我們靜靜的等待10秒鐘過去,然后再點開該文件,看看是否能夠成功:
我們發(fā)現(xiàn)內(nèi)容的確已經(jīng)變成了“abcdef”,由此也就完成了續(xù)傳。
相關(guān)閱讀
0基礎(chǔ) 0學(xué)費 15天面授
有基礎(chǔ) 直達就業(yè)
業(yè)余時間 高薪轉(zhuǎn)行
工作1~3年,加薪神器
工作3~5年,晉升架構(gòu)
提交申請后,顧問老師會電話與您溝通安排學(xué)習(xí)
初級 202925
初級 203221
初級 202629
初級 203743