- Java核心技術(shù)·卷Ⅱ:高級特性(原書第10版)
- (美)凱S.霍斯特曼
- 2194字
- 2020-10-30 18:10:45
2.6.1 內(nèi)存映射文件的性能
在本節(jié)的末尾,你可以發(fā)現(xiàn)一個計算傳統(tǒng)的文件輸入和內(nèi)存映射文件的CRC32校驗和的程序。在同一臺機(jī)器上,我們對JDK的jre/lib目錄中的37MB的rt.jar文件用不同的方式來計算校驗和,記錄下來的時間數(shù)據(jù)如表2-5所示。
表2-5 文件操作的處理時間數(shù)據(jù)

正如你所見,在這臺特定的機(jī)器上,內(nèi)存映射比使用帶緩沖的順序輸入要稍微快一點,但是比使用RandomAccessFile快很多。
當(dāng)然,精確的值因機(jī)器不同會產(chǎn)生很大的差異,但是很明顯,與隨機(jī)訪問相比,性能提高總是很顯著的。另一方面,對于中等尺寸文件的順序讀入則沒有必要使用內(nèi)存映射。
java.nio包使內(nèi)存映射變得十分簡單,下面就是我們需要做的。
首先,從文件中獲得一個通道(channel),通道是用于磁盤文件的一種抽象,它使我們可以訪問諸如內(nèi)存映射、文件加鎖機(jī)制以及文件間快速數(shù)據(jù)傳遞等操作系統(tǒng)特性。

然后,通過調(diào)用FileChannel類的map方法從這個通道中獲得一個ByteBuffer。你可以指定想要映射的文件區(qū)域與映射模式,支持的模式有三種:
·FileChannel.MapMode.READ_ONLY:所產(chǎn)生的緩沖區(qū)是只讀的,任何對該緩沖區(qū)寫入的嘗試都會導(dǎo)致ReadOnlyBufferException異常。
·FileChannel.MapMode.READ_WRITE:所產(chǎn)生的緩沖區(qū)是可寫的,任何修改都會在某個時刻寫回到文件中。注意,其他映射同一個文件的程序可能不能立即看到這些修改,多個程序同時進(jìn)行文件映射的確切行為是依賴于操作系統(tǒng)的。
·FileChannel.MapMode.PRIVATE:所產(chǎn)生的緩沖區(qū)是可寫的,但是任何修改對這個緩沖區(qū)來說都是私有的,不會傳播到文件中。
一旦有了緩沖區(qū),就可以使用ByteBuffer類和Buffer超類的方法讀寫數(shù)據(jù)了。
緩沖區(qū)支持順序和隨機(jī)數(shù)據(jù)訪問,它有一個可以通過get和put操作來移動的位置。例如,可以像下面這樣順序遍歷緩沖區(qū)中的所有字節(jié):

或者,像下面這樣進(jìn)行隨機(jī)訪問:

你可以用下面的方法來讀寫字節(jié)數(shù)組:

最后,還有下面的方法:

用來讀入在文件中存儲為二進(jìn)制值的基本類型值。正如我們提到的,Java對二進(jìn)制數(shù)據(jù)使用高位在前的排序機(jī)制,但是,如果需要以低位在前的排序方式處理包含二進(jìn)制數(shù)字的文件,那么只需調(diào)用

要查詢緩沖區(qū)內(nèi)當(dāng)前的字節(jié)順序,可以調(diào)用:

警告:這一對方法沒有使用set/get命名慣例。
要向緩沖區(qū)寫數(shù)字,可以使用下列的方法:


在恰當(dāng)?shù)臅r機(jī),以及當(dāng)通道關(guān)閉時,會將這些修改寫回到文件中。
程序清單2-5用于計算文件的32位的循環(huán)冗余校驗和(CRC32),這個數(shù)值就是經(jīng)常用來判斷一個文件是否已損壞的校驗和,因為文件損壞極有可能導(dǎo)致校驗和改變。java.util.zip包中包含一個CRC32類,可以使用下面的循環(huán)來計算一個字節(jié)序列的校驗和:

注意:對CRC算法有一個很精細(xì)的解釋,請查看http://www.relisoft.com/Science/CrcMath.html。
CRC計算的細(xì)節(jié)并不重要,我們只是將它作為一個有用的文件操作的實例來使用。(在實踐中,每次會以更大的工夫而不是一個字節(jié)為單位來讀取和更新數(shù)據(jù),而它們的速度差異并不明顯。)
應(yīng)該像下面這樣運(yùn)行程序:

程序清單2-5 memoryMap/MemoryMapTest.java



java.io.FileInputStream 1.0
·FileChannel getChannel()1.4
返回用于訪問這個輸入流的通道。
java.io.FileOutputStream 1.0
·FileChannel getChannel()1.4
返回用于訪問這個輸出流的通道。
java.io.RandomAccessFile1.0
·FileChannel getChannel()1.4
返回用于訪問這個文件的通道。
java.nio.channels.FileChannel 1.4
·static FileChannel open(Path path,OpenOption...options)7
打開指定路徑的文件通道,默認(rèn)情況下,通道打開時用于讀入。
參數(shù):path 打開通道的文件所在的路徑
options StandardOpenOption枚舉中的WRITE、APPEND、TRUNCATE_EXISTING、CREATE值
·MappedByteBuffer map(FileChannel.MapMode mode,long position,long size)
將文件的一個區(qū)域映射到內(nèi)存中。
參數(shù):mode FileChannel.MapMode類中的常量READ_ONLY、READ_WRITE、或PRIVATE之一
position 映射區(qū)域的起始位置
size 映射區(qū)域的大小
java.nio.Buffer 1.4
·boolean hasRemaining()
如果當(dāng)前的緩沖區(qū)位置沒有到達(dá)這個緩沖區(qū)的界限位置,則返回true。
·int limit()
返回這個緩沖區(qū)的界限位置,即沒有任何值可用的第一個位置。
java.nio.ByteBuffer 1.4
·byte get()
從當(dāng)前位置獲得一個字節(jié),并將當(dāng)前位置移動到下一個字節(jié)。
·byte get(int index)
從指定索引處獲得一個字節(jié)。
·ByteBuffer put(byte b)
向當(dāng)前位置推入一個字節(jié),并將當(dāng)前位置移動到下一個字節(jié)。返回對這個緩沖區(qū)的引用。
·ByteBuffer put(int index,byte b)
向指定索引處推入一個字節(jié)。返回對這個緩沖區(qū)的引用。
·ByteBuffer get(byte[]destination)
·ByteBuffer get(byte[]destination,int offset,int length)
用緩沖區(qū)中的字節(jié)來填充字節(jié)數(shù)組,或者字節(jié)數(shù)組的某個區(qū)域,并將當(dāng)前位置向前移動讀入的字節(jié)數(shù)個位置。如果緩沖區(qū)不夠大,那么就不會讀入任何字節(jié),并拋出BufferUnderflow Exception。返回對這個緩沖區(qū)的引用。
參數(shù):destination 要填充的字節(jié)數(shù)組
offset 要填充區(qū)域的偏移量
length 要填充區(qū)域的長度
·ByteBuffer put(byte[]source)
·ByteBuffer put(byte[]source,int offset,int length)
將字節(jié)數(shù)組中的所有字節(jié)或者給定區(qū)域的字節(jié)都推入緩沖區(qū)中,并將當(dāng)前位置向前移動寫出的字節(jié)數(shù)個位置。如果緩沖區(qū)不夠大,那么就不會讀入任何字節(jié),并拋出BufferUnderflow Exception。返回對這個緩沖區(qū)的引用。
參數(shù):source 要寫出的數(shù)組
offset 要寫出區(qū)域的偏移量
length 要寫出區(qū)域的長度
·Xxx getXxx()
·Xxx getXxx(int index)
·ByteBuffer putXxx(Xxx value)
·ByteBuffer putXxx(int index,Xxx value)
獲得或放置一個二進(jìn)制數(shù)。Xxx是Int、Long、Short、Char、Float或Double中的一個。
·ByteBuffer order(ByteOrder order)
·ByteOrder order()
設(shè)置或獲得字節(jié)順序,order的值是ByteOrder類的常量BIG_ENDIAN或LITTLE_ENDIAN中的一個。
·static ByteBuffer allocate(int capacity)
構(gòu)建具有給定容量的緩沖區(qū)。
·static ByteBuffer wrap(byte[]values)
構(gòu)建具有指定容量的緩沖區(qū),該緩沖區(qū)是對給定數(shù)組的包裝。
·CharBuffer asCharBuffer()
構(gòu)建字符緩沖區(qū),它是對這個緩沖區(qū)的包裝。對該字符緩沖區(qū)的變更將在這個緩沖區(qū)中反映出來,但是該字符緩沖區(qū)有自己的位置、界限和標(biāo)記。
java.nio.CharBuffer 1.4
·char get()
·CharBuffer get(char[]destination)
·CharBuffer get(char[]destination,int offset,int length)
從這個緩沖區(qū)的當(dāng)前位置開始,獲取一個char值,或者一個范圍內(nèi)的所有char值,然后將位置向前移動越過所有讀入的字符。最后兩個方法將返回this。
·CharBuffer put(char c)
·CharBuffer put(char[]source)
·CharBuffer put(char[]source,int offset,int length)
·CharBuffer put(String source)
·CharBuffer put(CharBuffer source)
從這個緩沖區(qū)的當(dāng)前位置開始,放置一個char值,或者一個范圍內(nèi)的所有char值,然后將位置向前移動越過所有被寫出的字符。當(dāng)放置的值是從CharBuffer讀入時,將讀入所有剩余字符。所有方法將返回this。
- Python 深度學(xué)習(xí)
- Mastering Scientific Computing with R
- Internet of Things with the Arduino Yún
- Oracle數(shù)據(jù)庫從入門到運(yùn)維實戰(zhàn)
- Data Analysis with IBM SPSS Statistics
- C語言程序設(shè)計案例式教程
- 零基礎(chǔ)學(xué)Java程序設(shè)計
- 零基礎(chǔ)入門學(xué)習(xí)Python
- QGIS By Example
- Advanced Express Web Application Development
- Lift Application Development Cookbook
- Web程序設(shè)計:ASP.NET(第2版)
- 軟件工程與UML案例解析(第三版)
- Anaconda數(shù)據(jù)科學(xué)實戰(zhàn)
- Dart:Scalable Application Development