記憶體映射文件時利用虛擬記憶體實現來將一個文件或者文件的一部分映射到記憶體中,然後整個文件就可以當作數組一樣的訪問,這個比傳統的文件操作要快得多,Java 使用記憶體映射文件首先需要從文件中獲取一個channel(通道),通道時磁碟文件的一個抽象,他使得我們可以訪問諸如記憶體映射、文件加鎖機制以及文件間快速數... ...
記憶體映射文件時利用虛擬記憶體實現來將一個文件或者文件的一部分映射到記憶體中,然後整個文件就可以當作數組一樣的訪問,這個比傳統的文件操作要快得多,Java 使用記憶體映射文件首先需要從文件中獲取一個channel(通道),通道時磁碟文件的一個抽象,他使得我們可以訪問諸如記憶體映射、文件加鎖機制以及文件間快速數據傳遞等操作系統特性,然後通過調用 FileChannel 類的 map 方法從這個通道獲取一個映射塊(ByteBuffer),然後就可以讀取/寫入文件塊內容,map 支持的模式有如下:
- FileChannel.MapMode.READ_ONLY:所產生的緩衝區是只讀的,如果對只讀的緩衝區進行寫操作,將會導致 ReadonlyBufferException 異常
- FileChannel.MapMode.READ_WRITE:所產生的緩衝區是可寫的,任何修改都會在某個時刻寫迴文件(寫入不是及時的)
- FileChannel.MapMode.PRIVATE:所產生的緩衝區是可寫的,但是任何修改對這個緩衝區來說都是私有的,不會傳播到文件中
映射文件示例代碼:
- 讀取文件:
Path filePath = Paths.get("D:\\我的游戲\\World of Warcraft\\Data\\data", "data.001");
long startTime = System.currentTimeMillis(); //獲取開始時間
try {
try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {
int size = 40960;
long readByteSize = 0;
ByteBuffer byteBuffer = ByteBuffer.allocate(size);
int readCount;
do {
readCount = channel.read(byteBuffer);
byte[] readBytes = new byte[byteBuffer.limit()];
// channel.read 後其 position 是 readCount,因此需要讀取數據時,需要重置 position = 0
byteBuffer.position(0);
for(int i=0;i< readBytes.length;i++){
readBytes[i] = byteBuffer.get();
}
byteBuffer.clear();
if (readCount != -1) {
readByteSize += readCount;
}
System.out.print("readCount +" + readCount + " readByteSize " + readByteSize + " ");
} while (readCount != -1);
}
} catch (IOException ex) {
ex.printStackTrace();
}
long endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程式運行時間: " + (endTime - startTime) + "ms");
- 寫入文件(使用
RandomAccessFile
和
MappedByteBuffer):
Random random = new Random();
Path writeFilePath = Paths.get("d:\\channel.dat");
startTime = System.currentTimeMillis(); //獲取開始時間
try {
byte[] buff = new byte[40960];
long position = 0;
long size = buff.length;
RandomAccessFile randomAccessFile = new RandomAccessFile(writeFilePath.toString(), "rw");
try (FileChannel outChannel = randomAccessFile.getChannel()) {
for (int i = 0; i < 1000; i++) {
random.nextBytes(buff);
MappedByteBuffer buffer = outChannel.map(FileChannel.MapMode.READ_WRITE, position, size);
buffer.put(buff);
position += size;
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
endTime = System.currentTimeMillis(); //獲取結束時間
System.out.println("程式運行時間: " + (endTime - startTime) + "ms");