關於JAVA中順序IO的基本操作

閒雲野鶴出家人發表於2021-11-22

關於JAVA中順序IO的基本操作


寫在前面

最近研究一下JAVA中的順序IO,在網路上找了一會兒,發現少有詳細的介紹,顧此在此處說說順序IO,才學疏淺,如有不對,望賜教。

什麼是順序IO

事實上JAVA具有很多操作檔案的方案(方法), 許多程式需要將一些事件記錄到本地儲存中,常見的如資料庫,MQ等,首先檔案是許多帶資料的塊組成的,傳統IO操作檔案具有一個定址過程(事實上硬體上也會存在尋道,旋轉延遲等因素),小檔案尚可,大檔案就比較消耗效能和時間,比如資料庫分配的檔案(本地),順序IO具備指定位置的功能,但是任然需要我們維護一個偏移量(遊標).

MappedByteBuffer

JAVA順序IO通過MappedByteBuffer實現,與傳統IO不同的是,MappedByteBuffer需要使用者提供一個位置(偏移量),詳細看以下程式碼:

mappedByteBuffer.position(index);
mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF_8));

程式碼中可見,通過MappedByteBuffer提供的api position();來指定位置(偏移量),put()進行寫操作,詳細如下。

寫操作

先看程式碼:

public int write(File file ,String content ,int index,long size){
RandomAccessFile randomAccessFile;
MappedByteBuffer mappedByteBuffer;
try {

randomAccessFile = new RandomAccessFile(file,"rw"); //1
FileChannel fileChannel = randomAccessFile.getChannel(); //2
mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE,0,size); //3

mappedByteBuffer.position(index); //4
mappedByteBuffer.put(content.getBytes(StandardCharsets.UTF_8)); //5
return mappedByteBuffer.position(); //6
}catch (Exception e){
e.printStackTrace();
}
return 0;
}
  • 上述程式碼中標註1位置中使用RandomAccessFile (隨機流)來開啟檔案,此流與傳統IO除了兼併讀寫之外,在一些底層實現方式上也均有不同,在此不多做介紹,感興趣可另尋資料,在此需記住,此處使用隨機流的作用為第二步做準備,且唯一,其中引數1為File物件,構造方法過載的引數1可為檔案路徑,引數2的取值可有4種,如下(取至JAVA官方文件):
  1. "r"僅供閱讀。呼叫結果物件的任何寫方法都會引發IOException。(Open for reading only. Invoking any of the write methods of the resulting object will cause an IOException to be thrown. )

  2. "rw"開放閱讀和寫作。如果該檔案不存在,那麼將嘗試建立它。(Open for reading and writing. If the file does not already exist then an attempt will be made to create it. )

  3. “rws”和“rw”一樣,對檔案內容或後設資料的每次更新都要同步寫入底層儲存裝置。(Open for reading and writing, as with "rw", and also require that every update to the file's content or metadata be written synchronously to the underlying storage device. )

  4. “rwd”和“rw”一樣,都是開啟的,可以讀寫,並且還要求對檔案內容的每次更新都要同步寫入底層儲存裝置。(Open for reading and writing, as with "rw", and also require that every update to the file's content be written synchronously to the underlying storage device. )

  • 上述程式碼中標註2位置中,通過隨機流獲取到一個讀寫兼併的通道,實際上獲取IO通道的方式並不僅僅只有此種方式,但是在此處需要注意的是,順序讀寫所需的通道需兼併讀寫(第一步中引數2取值需為:rw,rws,rwd),如果不是,則會觸發IO異常,除此之外,上述提到過使用其他方式也可以獲取到檔案IO通道,比如:
FileInputStream fileInputStream = new FileInputStream(file);
FileChannel fileChannel = fileInputStream.getChannel();

執行結果,標記3處丟擲異常:NonWritableChannelException
或者:

FileOutputStream fileInputStream = new FileOutputStream(file);
FileChannel fileChannel = fileInputStream.getChannel();

執行結果,標記3處丟擲異常:NonReadableChannelException
從上可以看到,不管是FileInputStream還是FileOutputStream獲取到的IO通道,均有侷限性,不適用MappedByteBuffer。

  • 上述程式碼中標記3位置中,通過IO通道將該檔案的內容(或某個區域)直接對映到記憶體中,並且對該記憶體做的修改直接會傳播到檔案(除了PRIVATE模式,後續介紹),通過FileChannel物件的map();api進行對映,引數一指定對映方式,有如下三種(取至JAVA官方文件):
  1. 只讀:任何修改結果緩衝區的嘗試都將導致丟擲ReadOnlyBufferException。(MapMode.READ_ONLY) (Read-only: Any attempt to modify the resulting buffer will cause a ReadOnlyBufferException to be thrown. (MapMode.READ_ONLY) )

  2. 讀/寫:對產生的緩衝區所做的更改最終將傳播到檔案;它們可能對對映了相同檔案的其他程式可見,也可能不可見。(MapMode.READ_WRITE) (Read/write: Changes made to the resulting buffer will eventually be propagated to the file; they may or may not be made visible to other programs that have mapped the same file. (MapMode.READ_WRITE) )

  3. Private:對產生的緩衝區所做的更改不會傳播到該檔案中,並且不會對對映了該檔案的其他程式可見;相反,它們將導致建立緩衝區修改部分的私有副本。(MapMode.PRIVATE) (Private: Changes made to the resulting buffer will not be propagated to the file and will not be visible to other programs that have mapped the same file; instead, they will cause private copies of the modified portions of the buffer to be created. (MapMode.PRIVATE) )

引數二代表從指定位置開始對映,0表示從頭開始對映全部內容,引數三表示要對映的區域大小,可超出檔案大小(如字元長度為3,此處可填寫6或者其他),但不可為負數或超出Integer.MAX_VALUE.
實際上到此處,IO通道已經完成了它的任務,可關閉。(在標記3之後任意位置可執行fileChannel.close()而不影響執行結果)
此處簡要說明了個引數的意思,要加深瞭解建議自己建立Demo並更改此處引數觀察執行結果。

  • 上述程式碼中標記4位置中,通過MappedByteBuffer物件的position(); API設定寫入位置,官方解釋如下:
    Sets this buffer's limit. If the position is larger than the new limit then it is set to the new limit. If the mark is defined and larger than the new limit then it is discarded.

  • 上述程式碼中標記5位置中,將內容傳輸到緩衝區,可理解為寫入,因為緩衝區的變動會傳播到實際檔案中,除了PRIVATE。

  • 上述程式碼中標記6位置中,返回下一次操作時的位置。

此篇文章簡要說明了一下JAVA順序IO,有些地方沒有詳細說明,會持續維護更新此篇文章,感謝大家。

相關文章