日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java流与文件——内存映射文件

發(fā)布時間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java流与文件——内存映射文件 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

【0】README

0.1) 本文描述轉自 core java volume 2, 旨在理解 java流與文件——內存映射文件 的相關知識;
0.2)內存映射文件的目的是: 提高訪問速度, 緩沖區(qū)Buffer;
0.3) 本文干貨源代碼均為原創(chuàng), for source code , please visit https://github.com/pacosonTang/core-java-volume/blob/master/coreJavaAdvanced/chapter1/MemoryMapTest.java


【1】intro to 內存映射文件

1.1)大多數(shù)os 都利用 虛擬內存實現(xiàn)來將 一個文件或文件的一部分映射到 內存中;
1.2)java.nio 包使內存映射變得簡單, 下面是我們需要做的:

  • 1.2.1)首先,從文件中獲得一個通道, 通道是對 磁盤文件的一種抽象, 它使我們可以訪問諸如內存映射, 文件加鎖機制以及文件間快速數(shù)據(jù)傳遞等操作系統(tǒng)特性;(干貨——通道的定義,即對磁盤文件的抽象)
    FileChannel channel = FIleChannel.open(path , options);
  • 1.2.2) 然后, 調用FileChannel 類的map方法從這個通道中獲得一個 ByteBuffer。 你可以指定想要映射的文件區(qū)域與映射模式, 支持的模式有三種(Model):
    • M1)FileChannel.MapMode.READ_ONLY: 所產生的緩沖區(qū)是只讀的, 任何對該緩沖區(qū)寫入都會產生異常;
    • M2)FileChannel.MapMode.READ_WRITE:所產生的緩沖區(qū)是可寫的;任何修改都會在這個時刻寫回到文件中;
    • M3)FileChannel.MapMode.PRIVATE: 所產生的緩沖區(qū)是可寫的, 但是任何修改對這個緩沖區(qū)來說都是私有的,不會傳播到文件中;

1.3)一旦有了緩沖區(qū),就可以使用 ByteBuffer 類 和 Buffer 超類的方法讀寫數(shù)據(jù)了;

  • 1.3.1)緩沖區(qū)支持順序和隨機數(shù)據(jù)訪問, 它有一個可以通過get 和 put 操作來移動的位置;如, 像下面這樣遍歷緩沖區(qū)中的所有字節(jié):
    while(buffer.hasRemaining)
    {
    byte b = buffer.get();
    }
  • 1.3.2)或者像下面這樣進行隨機訪問:
    for(i=0;i
CRC32 crc = new CRC32(); while(more bytes)crc.update(next byte) long checksum = crc.getValue();


【2】緩沖區(qū)數(shù)據(jù)結構

2.1)在使用內存映射時, 我們創(chuàng)建了單一的緩沖區(qū)橫跨整個文件或我們感興趣的文件區(qū)域。我們還可以使用更多的緩沖區(qū)來讀寫大小適度的信息塊;
2.2)本節(jié)將簡要介紹Buffer 對象上的基本操作。

  • 2.2.1)緩沖區(qū)定義:緩沖區(qū)是由具有相同類型的數(shù)值構成的數(shù)組,Buffer 類是一個抽象類, 它有眾多的具體子類,包括ByteBuffer, CharBuffer, DoubleBuffer, IntBuffer, LongBuffer, ShortBuffer ; (干貨——緩沖區(qū)定義)
    Attention) StringBufffer 類與這些緩沖區(qū)沒有關系;
  • 2.2.2)最常用的是ByteBuffer 和 CharBuffer; (干貨——最常用Buffer的是ByteBuffer 和 CharBuffer)
  • 2.2.3)每個緩沖區(qū)都具有: (干貨——緩沖區(qū)的功能)

    • 2.2.3.1)一個容量: 它永遠不能改變;
    • 2.2.3.2)一個讀寫位置: 下一個值將在此進行讀寫;
    • 2.2.3.3)一個界限: 超過它進行讀寫是沒有意義的;
    • 2.2.3.4)一個可選標記:用于重復一個讀入或寫出操作;
    • 2.2.3.5)這些值滿足下面的條件: 0 <= 標記<=讀寫位置 <=界限 <=容量; (干貨——緩沖區(qū)中給定標記,讀寫位置,界限,容量的大小關系)
  • 2.2.4)使用緩沖區(qū)的主要目的是執(zhí)行寫, 然后讀入循環(huán)。

    • 2.2.4.1)put方法:將值添加到緩沖區(qū);
    • 2.2.4.2)flip方法:將界限設置到當前位置,并把位置復位到0;
    • 2.2.4.3)remaining方法: 現(xiàn)在在 remaining 方法返回整數(shù)時(它返回的值是 “界限—位置”),不斷地調用get方法;
    • 2.2.4.4)clear方法: 在我們將緩沖區(qū)的所有值都讀入后, 調用clear 使緩沖區(qū)為下一次寫循環(huán)做好準備。 clear 方法將位置復位到0, 并將界限復位到容量;
    • 2.2.4.5)rewind 或 mark/reset方法: 如果你想重讀緩沖區(qū), 可以使用 rewind或 mark/reset 方法;
    • 2.2.4.6)ByteBuffer.allocate 或 ByteBuffer.wrap : 要獲得緩沖區(qū),調用它們;
    • 2.2.4.7)用來自某個通道的數(shù)據(jù)填充緩沖區(qū), 或用緩沖區(qū)的數(shù)據(jù)寫出到通道: (干貨代碼——用來自某個通道的數(shù)據(jù)填充緩沖區(qū), 或用緩沖區(qū)的數(shù)據(jù)寫出到通道)
ByteBuffer buffer = ByteBuffer.allocate(RECORD_SIZE); channel.read(buffer); channel.position(newpos); buffer.flip(); channel.write(buffer);


【3】文件加鎖機制(多個程序同時修改同一個文件的情形)

3.1)problem + solution

  • 3.1.1)problem: 多個程序同時修改同一個文件的情形, 這些程序需要以某種方式進行通信, 不然文件很容易損壞;
  • 3.1.2)solution: 文件鎖可以解決這個問題, 它可以控制對文件或文件中的某個范圍的字節(jié) 的訪問; (干貨——文件鎖的功能)

3.2)看個荔枝:假設應用程序將用戶個人信息存儲在一個配置文件中, 當用戶同時調用兩個線程操作該文件時;

  • 3.2.1)第一個線程,應該鎖定該文件, 而第二個線程發(fā)現(xiàn)這個文件被鎖定了, 它必須決策是等待直至解鎖還是跳過這個寫操作過程;(干貨——文件加鎖機制后線程如何決策)
FileChannel channel = FileChannel.open(path); FileLock lock = channle.lock(); 或 FileLock lock = channel.tryLock();

Attention): 通道是對磁盤文件的一種抽象; (干貨——再次提醒通道定義,即通道是對磁盤文件的一種抽象)

對上述代碼的分析(Analysis):

  • A1)第一個調用會阻塞直至可獲得鎖, 而第二個調用將立即返回, 要么返回鎖,要么在所不可獲得的情況下返回null;
  • A2)這個文件將保持鎖定狀態(tài),直至這個通道被關閉, 或者在鎖上調用 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數(shù)據(jù)域的含義)
  • 3.3.2)并非所有的os 都支持共享鎖, 因此你可能會請求共享鎖的時候得到的是獨占的鎖。調用 FileLock 類的 isShared 方法可以查詢你所持有的鎖的類型; (干貨——共享鎖和獨占鎖的定義)

Attention)如果你鎖定了文件的尾部, 而這個文件的長度隨后增長超過了鎖定的部分, 那么增長出來的額外區(qū)域是未鎖定的, 要想鎖定所有的字節(jié),可以用 Long.MAX_VALUE 來表示尺寸;

3.4)要確保在操作完成時釋放鎖,與往常一樣, 最好在一個 try 語句中執(zhí)行釋放鎖的操作:

try(FileLock lock = channle.lock()) {access th elocked file or segment }

對以上代碼的分析(Analysis):

  • A1)查看 tryLock API, 你會發(fā)現(xiàn)(以下內容轉自 java SE 8 API): (干貨中的干貨——shared標識的排他鎖或共享鎖與StandardOpenOption的對應關系)
public abstract FileLock tryLock(long position,long size,boolean shared)throws IOException Parameters: position - The position at which the locked region is to start; must be non-negative size - The size of the locked region; must be non-negative, and the sum position + size must be non-negative shared - true to request a shared lock, false to request an exclusive lock
  • 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)在某些系統(tǒng)中,文件加鎖僅僅是建議性的, 如果一個應用未能獲得鎖,它仍舊可以向被另一個應用并發(fā)鎖定的文件執(zhí)行寫操作;
  • A2)在某些系統(tǒng)中, 不能在鎖定一個文件的同時將其映射到內存中;
  • A3)文件鎖是由整個 java 虛擬機持有的。 如果有兩個程序是由同一個虛擬機啟動的, 那么他們不可能每一個都獲得一個在同一個文件上的鎖。當調用lock 或 tryLock 方法時, 如果虛擬機已經在同一個文件上持有另一個重疊的鎖,那么這兩個方法將拋出 OverlappingFileLockException;
  • A4)在一些系統(tǒng)中, 關閉一個通道會釋放由 java 虛擬機持有的底層文件上的所有鎖。 因此, 在同一個鎖定文件上應該避免使用多個通道;(干貨——在同一個鎖定文件上應該避免使用多個通道)
  • A5)在網絡文件系統(tǒng)上鎖定文件時高度依賴于系統(tǒng) 的, 因此應該盡量避免;

總結

以上是生活随笔為你收集整理的java流与文件——内存映射文件的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。