Java文件斷點續(xù)傳實現(xiàn)原理解析
一、作用:
隨機流(RandomAccessFile)不屬于IO流,支持對文件的讀取和寫入隨機訪問。
二、隨機訪問文件原理:
首先把隨機訪問的文件對象看作存儲在文件系統(tǒng)中的一個大型 byte 數(shù)組,然后通過指向該 byte 數(shù)組的光標(biāo)或索引(即:文件指針 FilePointer)在該數(shù)組任意位置讀取或?qū)懭肴我鈹?shù)據(jù)。
三、相關(guān)方法說明:
1、對象聲明:RandomAccessFile raf = newRandomAccessFile(File file, String mode);
其中參數(shù) mode 的值可選 "r":可讀,"w" :可寫,"rw":可讀性;
2、獲取當(dāng)前文件指針位置:int RandowAccessFile.getFilePointer();
3、改變文件指針位置(相對位置、絕對位置):
1> 絕對位置:RandowAccessFile.seek(int index);
2> 相對位置:RandowAccessFile.skipByte(int step); 相對當(dāng)前位置
4、給寫入文件預(yù)留空間:RandowAccessFile.setLength(long len);
斷點續(xù)傳實現(xiàn)原理:
1)下載斷開的時候,記錄文件斷點的位置position;
2)繼續(xù)下載的時候,通過RandomAccessFile找到之前的position位置開始下載
實際操作:
我們在D盤的根目錄下創(chuàng)建一個名為”test.txt”的文件,文件內(nèi)容很簡單,如圖所示:

沒錯,我們輸入的內(nèi)容就是簡單的6個英語字母。然后我們右鍵→屬性:

我們要實現(xiàn)的效果很簡單:將在D盤的”test.txt”文件寫入到E盤當(dāng)中,但中途我們會模擬一次”中斷”行為,然后在重新繼續(xù)上傳,最終完成整個過程。
也就是說,我們這里將會把“D盤”視作一臺電腦,并且直接將”E盤”視作一臺服務(wù)器。那么這樣我們甚至都不再與http協(xié)議扯上半毛錢關(guān)系了,(當(dāng)然實際開發(fā)我們肯定是還是得與它扯上關(guān)系的 ^<^),從而只關(guān)心最基本的文件讀寫的”斷”和”續(xù)”的原理是怎么樣的。
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) {
// 源文件與目標(biāo)文件
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) {
} 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 (Exception e) {
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) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class FileAccessException extends Exception {
}
總結(jié)一下,我們在這次改動當(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)容如下:

沒錯,這個時候我們發(fā)現(xiàn)內(nèi)容只有“abc”。這是在我們預(yù)料以內(nèi)的,因為我們的程序模擬在文件上傳了3個字節(jié)的時候發(fā)生了中斷。
Ok,我們靜靜的等待10秒鐘過去,然后再點開該文件,看看是否能夠成功:

通過截圖我們發(fā)現(xiàn)內(nèi)容的確已經(jīng)變成了“abc”,由此也就完成了續(xù)傳。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring?Boot?使用?SSE?方式向前端推送數(shù)據(jù)詳解
這篇文章主要介紹了Spring?Boot?使用SSE方式向前端推送數(shù)據(jù)詳解,SSE簡單的來說就是服務(wù)器主動向前端推送數(shù)據(jù)的一種技術(shù),它是單向的,也就是說前端是不能向服務(wù)器發(fā)送數(shù)據(jù)的2022-08-08
Spring Boot 整合mybatis 使用多數(shù)據(jù)源的實現(xiàn)方法
這篇文章主要介紹了Spring Boot 整合mybatis 使用多數(shù)據(jù)源的實現(xiàn)方法,需要的朋友可以參考下2018-03-03
SpringBoot對接clerk實現(xiàn)用戶信息獲取功能
Clerk是一個提供身份驗證和用戶管理的服務(wù),可以幫助開發(fā)者快速集成這些功能,下面我們就來看看如何使用Spring?Boot對接Clerk實現(xiàn)用戶信息的獲取吧2025-02-02
基于Java8并行流(parallelStream)的注意點
這篇文章主要介紹了Java8并行流(parallelStream)的注意點,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Java中mkdir()和mkdirs()的區(qū)別及說明
這篇文章主要介紹了Java中mkdir()和mkdirs()的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-11-11
Eclipse中創(chuàng)建Web項目最新方法(2023年)
在Java開發(fā)人員中,最常用的開發(fā)工具應(yīng)該就是Eclipse,下面這篇文章主要給大家介紹了關(guān)于Eclipse中創(chuàng)建Web項目2023年最新的方法,需要的朋友可以參考下2023-09-09
@Autowired自動裝配,@Bean注入@Primary,@Qualifier優(yōu)先級講解
這篇文章主要介紹了@Autowired自動裝配,@Bean注入@Primary,@Qualifier優(yōu)先級,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09

