自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

為什么隨機讀寫比按順序讀寫文件就是快?

開發(fā) 前端
本文主要圍繞 RandomAccessFile 類的基本概念和常用方法,做了一次簡單的知識總結(jié),該類是 IO 流體系中功能最豐富的文件內(nèi)容訪問類,既可以讀取文件中任意位置的內(nèi)容,也可以向文件任意位置寫入數(shù)據(jù)。

一、背景介紹

RandomAccessFile 類,也被稱為隨機訪問文件類。

RandomAccessFile 可以說是 Java 體系中功能最為豐富的文件操作類,相比之前介紹的通過字節(jié)流或者字符流接口方式讀寫文件,RandomAccessFile 類可以跳轉(zhuǎn)到文件的任意位置處進行讀寫數(shù)據(jù),而無需把文件從頭讀到尾,因此讀寫性能上要快很多,但是該類僅限于操作文件,不能訪問其他的 IO 設(shè)備,如網(wǎng)絡(luò)、內(nèi)存映像等。

所以如果需要訪問文件的部分內(nèi)容,而不是把文件從頭讀到尾,使用 RandomAccessFile 將是更好的選擇。

實際上,雖然RandomAccessFile類具備隨機讀寫數(shù)據(jù)的功能,但是它既不是InputStream的子類,也不是OutputStream的子類,絕大部分的方法都是從零開始寫的,這可能是因為  RandomAccessFile 需要在文件里面前后移動,它的行為與其它的 I/O 類有著根本性的不同,所以相對比較獨立。

RandomAccessFile對象類中內(nèi)置了一個位置指示器,可以指向當(dāng)前讀寫處的位置,當(dāng)讀寫 n 個字節(jié)后,文件指示器將指向這 n 個字節(jié)后的下一個字節(jié)處。剛打開文件時,文件指示器指向文件的開頭處,當(dāng)移動文件指示器到新的位置時,隨后的讀寫將從新的位置開始,這是它與其他的文件讀寫方式最大的不同。

基本上,RandomAccessFile的工作方式是,結(jié)合DataInputStream和DataOutputStream類完成數(shù)據(jù)的讀寫,再加上自己的一些方法,比如定位用的 getFilePointer方法,在文件里移動用的seek方法,以及判斷文件大小length方法、跳過多少字節(jié)數(shù)的skipBytes方法等,來完成文件的隨機訪問和讀寫操作。

具體怎么使用呢,我們一起來看看!

二、RandomAccessFile 類基本介紹

下面先來看看一個簡單的例子。

// 獲取隨機訪問文件對象
RandomAccessFile raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {
    // 寫入數(shù)據(jù),1個int占4個字節(jié)
    raf.writeInt(i);
}
raf.close();

System.out.println("================修改前的內(nèi)容===============" );
// 重新獲取隨機訪問文件對象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {
    System.out.println("Value:" + i + ": " + raf.readInt());
}
raf.close();

// 重新獲取隨機訪問文件對象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
// 設(shè)置文件指針偏移量,從0開始,直接將文件指針移到第6個int數(shù)據(jù)后面(1個int占4個字節(jié))
raf.seek(5 * 4);
//覆蓋第6個int數(shù)據(jù)
raf.writeInt(16);
raf.close();

System.out.println("================修改后的內(nèi)容===============" );
// 重新獲取隨機訪問文件對象
raf = new RandomAccessFile(new File("randomFileDemo.txt"), "rw");
for (int i = 0; i < 10; i++) {
    System.out.println("Value:" + i + ": " + raf.readInt());
}
raf.close();

輸出結(jié)果:

================修改前的內(nèi)容===============
Value:0: 0
Value:1: 1
Value:2: 2
Value:3: 3
Value:4: 4
Value:5: 5
Value:6: 6
Value:7: 7
Value:8: 8
Value:9: 9
================修改后的內(nèi)容===============
Value:0: 0
Value:1: 1
Value:2: 2
Value:3: 3
Value:4: 4
Value:5: 16
Value:6: 6
Value:7: 7
Value:8: 8
Value:9: 9

RandomAccessFile類為用戶提供了兩種構(gòu)造方法,具體操作方式如下:

// 第一種構(gòu)造方法:指定 file 對象和讀寫模式
RandomAccessFile raf = new RandomAccessFile(File file, String mode);

// 第二種構(gòu)造方法:指定 filename 路徑和讀寫模式
RandomAccessFile raf = new RandomAccessFile(String filename, String mode);

其實第二種構(gòu)造方法也是new File()出來,再調(diào)用第一種構(gòu)造方法,兩者都可以獲取隨機訪問文件對象。

至于mode,表示以何種方式打開文件,Java給開發(fā)者提供了四種mode值,具體解釋如下!

圖片圖片

值得注意的地方是,"rw"模式下,Java 并不強求指定的路徑下一定存在某個文件,假如文件不存在,會自動創(chuàng)建。

RandomAccessFile類為用戶提供的方法比較多,我們可以關(guān)注下幾個重要的方法即可,詳細(xì)方法如下圖!

圖片圖片

方法的使用,可以參考如下樣例:

RandomAccessFile file = new RandomAccessFile("file.txt", "rw");
// 以下向file文件中寫數(shù)據(jù)
file.writeInt(20);// 占4個字節(jié)
file.writeDouble(8.236598);// 占8個字節(jié)
file.writeUTF("這是一個UTF字符串");// 這個長度寫在當(dāng)前文件指針的前兩個字節(jié)處,可用readShort()讀取
file.writeBoolean(true);// 占1個字節(jié)
file.writeShort(395);// 占2個字節(jié)
file.writeLong(2325451L);// 占8個字節(jié)
file.writeUTF("又是一個UTF字符串");
file.writeFloat(35.5f);// 占4個字節(jié)
file.writeChar('a');// 占2個字節(jié)

file.seek(0);// 把文件指針位置設(shè)置到文件起始處

// 以下從file文件中讀數(shù)據(jù),要注意文件指針的位置
System.out.println("——————從file文件指定位置讀數(shù)據(jù)——————");
System.out.println(file.readInt());
System.out.println(file.readDouble());
System.out.println(file.readUTF());

file.skipBytes(3);// 將文件指針跳過3個字節(jié),本例中即跳過了一個boolean值和short值。
System.out.println(file.readLong());

file.skipBytes(file.readShort()); // 跳過文件中“又是一個UTF字符串”所占字節(jié),注意readShort()方法會移動文件指針,所以不用加2。
System.out.println(file.readFloat());

//以下演示文件復(fù)制操作
System.out.println("——————文件復(fù)制(從file到fileCopy)——————");
file.seek(0);
RandomAccessFile fileCopy=new RandomAccessFile("fileCopy.txt","rw");
int len=(int)file.length();//取得文件長度(字節(jié)數(shù))
byte[] b=newbyte[len];
file.readFully(b);//讀取全部內(nèi)容
fileCopy.write(b);//全部寫入目標(biāo)文件
System.out.println("復(fù)制完成!");

根據(jù)以上的方法介紹,我們可以利用RandomAccessFile實現(xiàn)一個在任意位置插入數(shù)據(jù)的操作,具體實例如下:

public class RandomAccessFileTest1 {

    /**
     * 插入數(shù)據(jù)
     * @param skip 跳過多少過字節(jié)進行插入數(shù)據(jù)
     * @param str 要插入的字符串
     * @param fileName 文件路徑
     */
    public static void insert(long skip, String str, String fileName){
        try {
            RandomAccessFile raf = new RandomAccessFile(fileName,"rw");
            if(skip <  0 || skip > raf.length()){
                System.out.println("跳過字節(jié)數(shù)無效");
                return;
            }
            byte[] b = str.getBytes();
            raf.setLength(raf.length() + b.length);
            // 將尾部數(shù)據(jù)進行遷移
            for(long i = raf.length() - 1; i > b.length + skip - 1; i--){
                raf.seek(i - b.length);
                byte temp = raf.readByte();
                raf.seek(i);
                raf.writeByte(temp);
            }
            // 從指定的位置,開始覆寫數(shù)據(jù)
            raf.seek(skip);
            raf.write(b);
            raf.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法測試
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) {
        insert(0, "一起學(xué)習(xí)Java", "test.txt");
        insert(0, "Hello,", "test.txt");
    }
}

文件內(nèi)容結(jié)果如下:

Hello,一起學(xué)習(xí)Java

三、RandomAccessFile 類的應(yīng)用

在實際的開發(fā)過程中,RandomAccessFile 的一個重要應(yīng)用場景就是網(wǎng)絡(luò)請求中的文件多線程下載及斷點續(xù)傳。

首先將文件分成幾塊,然后每塊用不同的線程進行下載,下面是一個利用多線程在寫文件時的例子:

public class RandomAccessFileTest2 {

    public static void main(String[] args) throws Exception {
        // 預(yù)分配文件所占的磁盤空間,磁盤中會創(chuàng)建一個指定大小的文件
        RandomAccessFile raf = new RandomAccessFile("test.txt", "rw");
        raf.setLength(1024*1024); // 預(yù)分配 1M 的文件空間
        raf.close();

        // 所要寫入的文件內(nèi)容
        String s1 = "第一個字符串";
        String s2 = "第二個字符串";
        String s3 = "第三個字符串";
        String s4 = "第四個字符串";
        String s5 = "第五個字符串";

        // 利用多線程同時寫入一個文件
        new FileWriteThread(1024*1,s1.getBytes()).start(); // 從文件的1024字節(jié)之后開始寫入數(shù)據(jù)
        new FileWriteThread(1024*2,s2.getBytes()).start(); // 從文件的2048字節(jié)之后開始寫入數(shù)據(jù)
        new FileWriteThread(1024*3,s3.getBytes()).start(); // 從文件的3072字節(jié)之后開始寫入數(shù)據(jù)
        new FileWriteThread(1024*4,s4.getBytes()).start(); // 從文件的4096字節(jié)之后開始寫入數(shù)據(jù)
        new FileWriteThread(1024*5,s5.getBytes()).start(); // 從文件的5120字節(jié)之后開始寫入數(shù)據(jù)
    }
}

class FileWriteThread extends Thread{
    privateint skip;
    privatebyte[] content;

    public FileWriteThread(int skip,byte[] content){
        this.skip = skip;
        this.content = content;
    }

    @Override
    public void run(){
        RandomAccessFile raf = null;
        try {
            // 利用線程在文件的指定位置寫入指定數(shù)據(jù)
            raf = new RandomAccessFile("test.txt", "rw");
            raf.seek(skip);
            raf.write(content);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                raf.close();
            } catch (Exception e) {
            }
        }
    }
}

四、小結(jié)

本文主要圍繞 RandomAccessFile 類的基本概念和常用方法,做了一次簡單的知識總結(jié),該類是 IO 流體系中功能最豐富的文件內(nèi)容訪問類,既可以讀取文件中任意位置的內(nèi)容,也可以向文件任意位置寫入數(shù)據(jù)。

當(dāng)然 RandomAccessFile 當(dāng)讀寫大文件的時候,會出現(xiàn)內(nèi)存溢出問題,此時可以采用內(nèi)存映射文件方式進行讀寫數(shù)據(jù),關(guān)于技術(shù)會在后期的文章中進行介紹。

五、參考

1、https://www.cnblogs.com/xrq730/p/4888288.html

2、https://blog.csdn.net/akon_vm/article/details/7429245

責(zé)任編輯:武曉燕 來源: 潘志的技術(shù)筆記
相關(guān)推薦

2021-02-26 20:55:56

JavaNIO隨機

2024-05-15 09:41:22

樂觀鎖編程

2016-12-14 12:02:01

StormHadoop大數(shù)據(jù)

2017-02-14 14:20:02

StormHadoop

2022-05-07 07:35:44

工具讀寫鎖Java

2024-06-11 00:01:00

并發(fā)validate場景

2017-03-23 14:37:19

WebAssemblyasm.js編程

2019-10-18 09:40:19

程序員固態(tài)硬盤Linux

2021-01-21 07:53:29

面試官Promis打印e

2023-04-07 08:17:39

fasthttp場景設(shè)計HTTP

2020-07-17 19:31:19

PythonR編程

2021-08-05 10:00:02

Python編程語言

2024-01-01 08:10:40

Go語言map

2024-01-05 08:45:35

Go語言map

2013-05-27 10:58:10

propertiesJava語言

2021-04-02 06:35:49

Bash讀寫文件Linux

2010-07-16 09:06:57

Perl文件

2010-11-19 11:32:25

Oracle存儲過程

2023-10-04 18:29:24

NFS小文件業(yè)務(wù)

2018-01-09 18:46:44

數(shù)據(jù)庫架構(gòu)讀寫分離
點贊
收藏

51CTO技術(shù)棧公眾號