java流与文件——内存映射文件
【0】README
0.1) 本文描述轉自 core java volume 2, 旨在理解 java流與文件——內存映射文件 的相關知識;
0.2)內存映射文件的目的是: 提高訪問速度, 緩沖區Buffer;
0.3) 本文干貨源代碼均為原創, for source code , please visit https://github.com/pacosonTang/core-java-volume/blob/master/coreJavaAdvanced/chapter1/MemoryMapTest.java
【1】intro to 內存映射文件
1.1)大多數os 都利用 虛擬內存實現來將 一個文件或文件的一部分映射到 內存中;
1.2)java.nio 包使內存映射變得簡單, 下面是我們需要做的:
- 1.2.1)首先,從文件中獲得一個通道, 通道是對 磁盤文件的一種抽象, 它使我們可以訪問諸如內存映射, 文件加鎖機制以及文件間快速數據傳遞等操作系統特性;(干貨——通道的定義,即對磁盤文件的抽象)
FileChannel channel = FIleChannel.open(path , options); - 1.2.2) 然后, 調用FileChannel 類的map方法從這個通道中獲得一個 ByteBuffer。 你可以指定想要映射的文件區域與映射模式, 支持的模式有三種(Model):
- M1)FileChannel.MapMode.READ_ONLY: 所產生的緩沖區是只讀的, 任何對該緩沖區寫入都會產生異常;
- M2)FileChannel.MapMode.READ_WRITE:所產生的緩沖區是可寫的;任何修改都會在這個時刻寫回到文件中;
- M3)FileChannel.MapMode.PRIVATE: 所產生的緩沖區是可寫的, 但是任何修改對這個緩沖區來說都是私有的,不會傳播到文件中;
1.3)一旦有了緩沖區,就可以使用 ByteBuffer 類 和 Buffer 超類的方法讀寫數據了;
- 1.3.1)緩沖區支持順序和隨機數據訪問, 它有一個可以通過get 和 put 操作來移動的位置;如, 像下面這樣遍歷緩沖區中的所有字節:
while(buffer.hasRemaining)
{
byte b = buffer.get();
} - 1.3.2)或者像下面這樣進行隨機訪問:
for(i=0;i
【2】緩沖區數據結構
2.1)在使用內存映射時, 我們創建了單一的緩沖區橫跨整個文件或我們感興趣的文件區域。我們還可以使用更多的緩沖區來讀寫大小適度的信息塊;
2.2)本節將簡要介紹Buffer 對象上的基本操作。
- 2.2.1)緩沖區定義:緩沖區是由具有相同類型的數值構成的數組,Buffer 類是一個抽象類, 它有眾多的具體子類,包括ByteBuffer, CharBuffer, DoubleBuffer, IntBuffer, LongBuffer, ShortBuffer ; (干貨——緩沖區定義)
Attention) StringBufffer 類與這些緩沖區沒有關系; - 2.2.2)最常用的是ByteBuffer 和 CharBuffer; (干貨——最常用Buffer的是ByteBuffer 和 CharBuffer)
2.2.3)每個緩沖區都具有: (干貨——緩沖區的功能)
- 2.2.3.1)一個容量: 它永遠不能改變;
- 2.2.3.2)一個讀寫位置: 下一個值將在此進行讀寫;
- 2.2.3.3)一個界限: 超過它進行讀寫是沒有意義的;
- 2.2.3.4)一個可選標記:用于重復一個讀入或寫出操作;
- 2.2.3.5)這些值滿足下面的條件: 0 <= 標記<=讀寫位置 <=界限 <=容量; (干貨——緩沖區中給定標記,讀寫位置,界限,容量的大小關系)
2.2.4)使用緩沖區的主要目的是執行寫, 然后讀入循環。
- 2.2.4.1)put方法:將值添加到緩沖區;
- 2.2.4.2)flip方法:將界限設置到當前位置,并把位置復位到0;
- 2.2.4.3)remaining方法: 現在在 remaining 方法返回整數時(它返回的值是 “界限—位置”),不斷地調用get方法;
- 2.2.4.4)clear方法: 在我們將緩沖區的所有值都讀入后, 調用clear 使緩沖區為下一次寫循環做好準備。 clear 方法將位置復位到0, 并將界限復位到容量;
- 2.2.4.5)rewind 或 mark/reset方法: 如果你想重讀緩沖區, 可以使用 rewind或 mark/reset 方法;
- 2.2.4.6)ByteBuffer.allocate 或 ByteBuffer.wrap : 要獲得緩沖區,調用它們;
- 2.2.4.7)用來自某個通道的數據填充緩沖區, 或用緩沖區的數據寫出到通道: (干貨代碼——用來自某個通道的數據填充緩沖區, 或用緩沖區的數據寫出到通道)
【3】文件加鎖機制(多個程序同時修改同一個文件的情形)
3.1)problem + solution
- 3.1.1)problem: 多個程序同時修改同一個文件的情形, 這些程序需要以某種方式進行通信, 不然文件很容易損壞;
- 3.1.2)solution: 文件鎖可以解決這個問題, 它可以控制對文件或文件中的某個范圍的字節 的訪問; (干貨——文件鎖的功能)
3.2)看個荔枝:假設應用程序將用戶個人信息存儲在一個配置文件中, 當用戶同時調用兩個線程操作該文件時;
- 3.2.1)第一個線程,應該鎖定該文件, 而第二個線程發現這個文件被鎖定了, 它必須決策是等待直至解鎖還是跳過這個寫操作過程;(干貨——文件加鎖機制后線程如何決策)
Attention): 通道是對磁盤文件的一種抽象; (干貨——再次提醒通道定義,即通道是對磁盤文件的一種抽象)
對上述代碼的分析(Analysis):
- A1)第一個調用會阻塞直至可獲得鎖, 而第二個調用將立即返回, 要么返回鎖,要么在所不可獲得的情況下返回null;
- A2)這個文件將保持鎖定狀態,直至這個通道被關閉, 或者在鎖上調用 release 方法;
3.3)你還可以通過下面的調用鎖定文件的一部分:
FileLock lock(long start, long size, boolean shared) 或 FileLock tryLock(long start, long size, boolean shared)- 3.3.1)如果shared 標志為 false, 則鎖定文件的目的是讀寫, 而如果為 true, 則這是一個共享鎖, 它允許多個進程從文件中讀入, 并組織任何進程獲得獨占鎖; (干貨——tryLock方法中shared數據域的含義)
- 3.3.2)并非所有的os 都支持共享鎖, 因此你可能會請求共享鎖的時候得到的是獨占的鎖。調用 FileLock 類的 isShared 方法可以查詢你所持有的鎖的類型; (干貨——共享鎖和獨占鎖的定義)
Attention)如果你鎖定了文件的尾部, 而這個文件的長度隨后增長超過了鎖定的部分, 那么增長出來的額外區域是未鎖定的, 要想鎖定所有的字節,可以用 Long.MAX_VALUE 來表示尺寸;
3.4)要確保在操作完成時釋放鎖,與往常一樣, 最好在一個 try 語句中執行釋放鎖的操作:
try(FileLock lock = channle.lock()) {access th elocked file or segment }對以上代碼的分析(Analysis):
- A1)查看 tryLock API, 你會發現(以下內容轉自 java SE 8 API): (干貨中的干貨——shared標識的排他鎖或共享鎖與StandardOpenOption的對應關系)
- A2)shared 屬性值(false=排他鎖, 而true=共享鎖)
- NonReadableChannelException - If shared is true but this channel was not opened for reading
- NonWritableChannelException - If shared is false but this channel was not opened for writing
- 也就是說,
- 共享鎖(shared = true): 對應的是 FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)
- 排他鎖(shared = false): 對應的是FileChannel channel = FileChannel.open(path, StandardOpenOption.WRITE)
- 以上對應關系出錯的話,會拋出異常;
Attention) 文件加鎖機制是依賴于os的, 下面是需要注意的:
- A1)在某些系統中,文件加鎖僅僅是建議性的, 如果一個應用未能獲得鎖,它仍舊可以向被另一個應用并發鎖定的文件執行寫操作;
- A2)在某些系統中, 不能在鎖定一個文件的同時將其映射到內存中;
- A3)文件鎖是由整個 java 虛擬機持有的。 如果有兩個程序是由同一個虛擬機啟動的, 那么他們不可能每一個都獲得一個在同一個文件上的鎖。當調用lock 或 tryLock 方法時, 如果虛擬機已經在同一個文件上持有另一個重疊的鎖,那么這兩個方法將拋出 OverlappingFileLockException;
- A4)在一些系統中, 關閉一個通道會釋放由 java 虛擬機持有的底層文件上的所有鎖。 因此, 在同一個鎖定文件上應該避免使用多個通道;(干貨——在同一個鎖定文件上應該避免使用多個通道)
- A5)在網絡文件系統上鎖定文件時高度依賴于系統 的, 因此應該盡量避免;
總結
以上是生活随笔為你收集整理的java流与文件——内存映射文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓开发微信页面布局(安卓开发微信)
- 下一篇: 如果被ddos应该怎么处理(如果被ddo