乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Java nio入門教程詳解(0021)

       360lec 2016-09-30
        3.4 內(nèi)存映射文件
        新的FileChannel類提供了一個(gè)名為map()的方法,該方法可以在一個(gè)打開的文件和一個(gè)特殊類型的ByteBuffer之間建立一個(gè)虛擬內(nèi)存映射(第一章中已經(jīng)歸納了什么是內(nèi)存映射文件以及它們?nèi)绾瓮摂M內(nèi)存交互)。在FileChannel上調(diào)用map()方法會(huì)創(chuàng)建一個(gè)由磁盤文件支持的虛擬內(nèi)存映射(virtual memory mapping)并在那塊虛擬內(nèi)存空間外部封裝一個(gè)MappedByteBuffer對(duì)象(參見圖 1-6)。
        由map()方法返回的MappedByteBuffer對(duì)象的行為在多數(shù)方面類似一個(gè)基于內(nèi)存的緩沖區(qū),只不過該對(duì)象的數(shù)據(jù)元素存儲(chǔ)在磁盤上的一個(gè)文件中。調(diào)用get()方法會(huì)從磁盤文件中獲取數(shù)據(jù),此數(shù)據(jù)反映該文件的當(dāng)前內(nèi)容,即使在映射建立之后文件已經(jīng)被一個(gè)外部進(jìn)程做了修改。通過文件映射看到的數(shù)據(jù)同您用常規(guī)方法讀取文件看到的內(nèi)容是完全一樣的。相似地,對(duì)映射的緩沖區(qū)實(shí)現(xiàn)一個(gè)put()會(huì)更新磁盤上的那個(gè)文件(假設(shè)對(duì)該文件您有寫的權(quán)限),并且您做的修改對(duì)于該文件的其他閱讀者也是可見的。
        通過內(nèi)存映射機(jī)制來訪問一個(gè)文件會(huì)比使用常規(guī)方法讀寫高效得多,甚至比使用通道的效率都高。因?yàn)椴恍枰雒鞔_的系統(tǒng)調(diào)用,那會(huì)很消耗時(shí)間。更重要的是,操作系統(tǒng)的虛擬內(nèi)存可以自動(dòng)緩存內(nèi)存頁(memory page)。這些頁是用系統(tǒng)內(nèi)存來緩存的,所以不會(huì)消耗Java虛擬機(jī)內(nèi)存堆(memory heap)。
        一旦一個(gè)內(nèi)存頁已經(jīng)生效(從磁盤上緩存進(jìn)來),它就能以完全的硬件速度再次被訪問而不需要再次調(diào)用系統(tǒng)命令來獲取數(shù)據(jù)。那些包含索引以及其他需頻繁引用或更新的內(nèi)容的巨大而結(jié)構(gòu)化文件能因內(nèi)存映射機(jī)制受益非常多。如果同時(shí)結(jié)合文件鎖定來保護(hù)關(guān)鍵區(qū)域和控制事務(wù)原子性,那您將能了解到內(nèi)存映射緩沖區(qū)如何可以被很好地利用。
        下面讓我們來看一下如何使用內(nèi)存映射:
        public abstract class FileChannel extends AbstractChannel implements ByteChannel, GatheringByteChannel, ScatteringByteChannel {
        // 這里僅列出部分API
        public abstract MappedByteBuffer map(MapMode mode, long position, long size)
        public static class MapMode
        {
        public static final MapMode READ_ONLY
        public static final MapMode READ_WRITE
        public static final MapMode PRIVATE
        }
        }
        可以看到,只有一種map()方法來創(chuàng)建一個(gè)文件映射。它的參數(shù)有mode,position和size。參數(shù)position和size同lock()方法的這兩個(gè)參數(shù)是一樣的(在前面的章節(jié)中已有討論)。我們可以創(chuàng)建一個(gè)MappedByteBuffer來代表一個(gè)文件中字節(jié)的某個(gè)子范圍。例如,要映射100到299(包含299)位置的字節(jié),可以使用下面的代碼:
        buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 100, 200);
        如果要映射整個(gè)文件則使用:
        buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
        與文件鎖的范圍機(jī)制不一樣,映射文件的范圍不應(yīng)超過文件的實(shí)際大小。如果您請(qǐng)求一個(gè)超出文件大小的映射,文件會(huì)被增大以匹配映射的大小。假如您給size參數(shù)傳遞的值是Integer.MAX_VALUE,文件大小的值會(huì)膨脹到超過2.1GB。即使您請(qǐng)求的是一個(gè)只讀映射,map()方法也會(huì)嘗試這樣做并且大多數(shù)情況下都會(huì)拋出一個(gè)IOException異常,因?yàn)榈讓拥奈募荒鼙恍薷?。該行為同之前討論的文件「空洞」的行為是一致的。詳情?qǐng)參考 3.3.1 節(jié)。
        FileChannel類定義了代表映射模式的常量,且是使用一個(gè)類型安全的枚舉而非數(shù)字值來定義這些常量。這些常量是FileChannel內(nèi)部定義的一個(gè)內(nèi)部類(inner class)的靜態(tài)字段,它們可以在編譯時(shí)被檢查類型,不過您可以像使用一個(gè)數(shù)值型常量那樣使用它們。
        同常規(guī)的文件句柄類似,文件映射可以是可寫的或只讀的。前兩種映射模式MapMode.READ_ONLY和MapMode.READ_WRITE意義是很明顯的,它們表示您希望獲取的映射只讀還是允許修改映射的文件。請(qǐng)求的映射模式將受被調(diào)用map()方法的FileChannel對(duì)象的訪問權(quán)限所限制。如果通道是以只讀的權(quán)限打開的而您卻請(qǐng)求MapMode.READ_WRITE模式,那么map()方法會(huì)拋出一個(gè)NonWritableChannelException異常;如果您在一個(gè)沒有讀權(quán)限的通道上請(qǐng)求MapMode.READ_ONLY映射模式,那么將產(chǎn)生NonReadableChannelException異常。不過在以read/write權(quán)限打開的通道上請(qǐng)求一個(gè)MapMode.READ_ONLY映射卻是允許的。MappedByteBuffer對(duì)象的可變性可以通過對(duì)它調(diào)用isReadOnly()方法來檢查。
        第三種模式MapMode.PRIVATE表示您想要一個(gè)寫時(shí)拷貝(copy-on-write)的映射。這意味著您通過put()方法所做的任何修改都會(huì)導(dǎo)致產(chǎn)生一個(gè)私有的數(shù)據(jù)拷貝并且該拷貝中的數(shù)據(jù)只有MappedByteBuffer實(shí)例可以看到。該過程不會(huì)對(duì)底層文件做任何修改,而且一旦緩沖區(qū)被施以垃圾收集動(dòng)作(garbage collected),那些修改都會(huì)丟失。盡管寫時(shí)拷貝的映射可以防止底層文件被修改,您也必須以read/write權(quán)限來打開文件以建立MapMode.PRIVATE映射。只有這樣,返回的MappedByteBuffer對(duì)象才能允許使用put()方法。
        寫時(shí)拷貝這一技術(shù)經(jīng)常被操作系統(tǒng)使用,以在一個(gè)進(jìn)程生成另一個(gè)進(jìn)程時(shí)管理虛擬地址空間(virtual address spaces)。使用寫時(shí)拷貝可以允許父進(jìn)程和子進(jìn)程共享內(nèi)存頁直到它們中的一方實(shí)際發(fā)生修改行為。在處理同一文件的多個(gè)映射時(shí)也有相同的優(yōu)勢(shì)(當(dāng)然,這需要底層操作系統(tǒng)的支持)。假設(shè)一個(gè)文件被多個(gè)MappedByteBuffer對(duì)象映射并且每個(gè)映射都是MapMode.PRIVATE模式,那么這份文件的大部分內(nèi)容都可以被所有映射共享。
        選擇使用MapMode.PRIVATE模式并不會(huì)導(dǎo)致您的緩沖區(qū)看不到通過其他方式對(duì)文件所做的修改。對(duì)文件某個(gè)區(qū)域的修改在使用MapMode.PRIVATE模式的緩沖區(qū)中都能反映出來,除非該緩沖區(qū)已經(jīng)修改了文件上的同一個(gè)區(qū)域。正如第一章中所描述的,內(nèi)存和文件系統(tǒng)都被劃分成了頁。當(dāng)在一個(gè)寫時(shí)拷貝的緩沖區(qū)上調(diào)用put()方法時(shí),受影響的頁會(huì)被拷貝,然后更改就會(huì)應(yīng)用到該拷貝中。具體的頁面大小取決于具體實(shí)現(xiàn),不過通常都是和底層文件系統(tǒng)的頁面大小時(shí)一樣的。如果緩沖區(qū)還沒對(duì)某個(gè)頁做出修改,那么這個(gè)頁就會(huì)反映被映射文件的相應(yīng)位置上的內(nèi)容。一旦某個(gè)頁因?yàn)閷懖僮鞫豢截?,之后就將使用該拷貝頁,并且不能被其他緩沖區(qū)或文件更新所修改。例3-5 的代碼詮釋了這一行為。
        您應(yīng)該注意到了沒有unmap()方法。也就是說,一個(gè)映射一旦建立之后將保持有效,直到MappedByteBuffer對(duì)象被施以垃圾收集動(dòng)作為止。同鎖不一樣的是,映射緩沖區(qū)沒有綁定到創(chuàng)建它們的通道上。關(guān)閉相關(guān)聯(lián)的FileChannel不會(huì)破壞映射,只有丟棄緩沖區(qū)對(duì)象本身才會(huì)破壞該映射。NIO設(shè)計(jì)師們之所以做這樣的決定是因?yàn)楫?dāng)關(guān)閉通道時(shí)破壞映射會(huì)引起安全問題,而解決該安全問題又會(huì)導(dǎo)致性能問題。如果您確實(shí)需要知道一個(gè)映射是什么時(shí)候被破壞的,他們建議使用虛引用(phantom references,參見java.lang.ref.PhantomReference)和一個(gè)cleanup線程。不過有此需要的概率是微乎其微的。
        MemoryMappedBuffer直接反映它所關(guān)聯(lián)的磁盤文件。如果映射有效時(shí)文件被在結(jié)構(gòu)上修改,就會(huì)產(chǎn)生奇怪的行為(當(dāng)然具體的行為是取決于操作系統(tǒng)和文件系統(tǒng)的)。MemoryMappedBuffer有固定的大小,不過它所映射的文件卻是彈性的。具體來說,如果映射有效時(shí)文件大小變化了,那么緩沖區(qū)的部分或全部?jī)?nèi)容都可能無法訪問,并將返回未定義的數(shù)據(jù)或者拋出未檢查的異常。關(guān)于被內(nèi)存映射的文件如何受其他線程或外部進(jìn)程控制這一點(diǎn),請(qǐng)務(wù)必小心對(duì)待。
        所有的MappedByteBuffer對(duì)象都是直接的,這意味著它們占用的內(nèi)存空間位于Java虛擬機(jī)內(nèi)存堆之外(并且可能不會(huì)算作 Java 虛擬機(jī)的內(nèi)存占用,不過這取決于操作系統(tǒng)的虛擬內(nèi)存模型)。
        因?yàn)镸appedByteBuffers也是ByteBuffers,所以能夠被傳遞SocketChannel之類通道的read()或write()以有效傳輸數(shù)據(jù)給被映射的文件或從被映射的文件讀取數(shù)據(jù)。如能再結(jié)合scatter/gather,那么從內(nèi)存緩沖區(qū)和被映射文件內(nèi)容中組織數(shù)據(jù)就變得很容易了。例 3-4 就是以此方式寫 HTTP 回應(yīng)的。3.4.1節(jié)中將描述一個(gè)傳輸數(shù)據(jù)給通道或從其他通道讀取數(shù)據(jù)的更加有效的方式。
        到現(xiàn)在為止,我們已經(jīng)討論完了映射緩沖區(qū)同其他緩沖區(qū)相同的特性,這些也是您會(huì)用得最多的。不過MappedByteBuffer還定義了幾個(gè)它獨(dú)有的方法:
        public abstract class MappedByteBuffer extends ByteBuffer {
        // 這里僅列出部分API
        public final MappedByteBuffer load()
        public final boolean isLoaded()
        public final MappedByteBuffer force()
        }
        當(dāng)我們?yōu)橐粋€(gè)文件建立虛擬內(nèi)存映射之后,文件數(shù)據(jù)通常不會(huì)因此被從磁盤讀取到內(nèi)存(這取決于操作系統(tǒng))。該過程類似打開一個(gè)文件:文件先被定位,然后一個(gè)文件句柄會(huì)被創(chuàng)建,當(dāng)您準(zhǔn)備好之后就可以通過這個(gè)句柄來訪問文件數(shù)據(jù)。對(duì)于映射緩沖區(qū),虛擬內(nèi)存系統(tǒng)將根據(jù)您的需要來把文件中相應(yīng)區(qū)塊的數(shù)據(jù)讀進(jìn)來。這個(gè)頁驗(yàn)證或防錯(cuò)過程需要一定的時(shí)間,因?yàn)閷⑽募?shù)據(jù)讀取到內(nèi)存需要一次或多次的磁盤訪問。某些場(chǎng)景下,您可能想先把所有的頁都讀進(jìn)內(nèi)存以實(shí)現(xiàn)最小的緩沖區(qū)訪問延遲。如果文件的所有頁都是常駐內(nèi)存的,那么它的訪問速度就和訪問一個(gè)基于內(nèi)存的緩沖區(qū)一樣了。
        load()方法會(huì)加載整個(gè)文件以使它常駐內(nèi)存。正如我們?cè)诘谝徽滤懻摰?,一個(gè)內(nèi)存映射緩沖區(qū)會(huì)建立與某個(gè)文件的虛擬內(nèi)存映射。此映射使得操作系統(tǒng)的底層虛擬內(nèi)存子系統(tǒng)可以根據(jù)需要將文件中相應(yīng)區(qū)塊的數(shù)據(jù)讀進(jìn)內(nèi)存。已經(jīng)在內(nèi)存中或通過驗(yàn)證的頁會(huì)占用實(shí)際內(nèi)存空間,并且在它們被讀進(jìn)RAM時(shí)會(huì)擠出最近較少使用的其他內(nèi)存頁。
        在一個(gè)映射緩沖區(qū)上調(diào)用load()方法會(huì)是一個(gè)代價(jià)高的操作,因?yàn)樗鼤?huì)導(dǎo)致大量的頁調(diào)入(page-in),具體數(shù)量取決于文件中被映射區(qū)域的實(shí)際大小。然而,load()方法返回并不能保證文件就會(huì)完全常駐內(nèi)存,這是由于請(qǐng)求頁面調(diào)入(demand paging)是動(dòng)態(tài)的。具體結(jié)果會(huì)因某些因素而有所差異,這些因素包括:操作系統(tǒng)、文件系統(tǒng),可用Java虛擬機(jī)內(nèi)存,最大Java虛擬機(jī)內(nèi)存,垃圾收集器實(shí)現(xiàn)過程等等。請(qǐng)小心使用load()方法,它可能會(huì)導(dǎo)致您不希望出現(xiàn)的結(jié)果。該方法的主要作用是為提前加載文件埋單,以便后續(xù)的訪問速度可以盡可能的快。
        對(duì)于那些要求近乎實(shí)時(shí)訪問(near-realtime access)的程序,解決方案就是預(yù)加載。但是請(qǐng)記住,不能保證全部頁都會(huì)常駐內(nèi)存,不管怎樣,之后可能還會(huì)有頁調(diào)入發(fā)生。內(nèi)存頁什么時(shí)候以及怎樣消失受多個(gè)因素影響,這些因素中的許多都是不受 Java 虛擬機(jī)控制的。JDK 1.4的NIO并沒有提供一個(gè)可以把頁面固定到物理內(nèi)存上的 API,盡管一些操作系統(tǒng)是支持這樣做的。
        對(duì)于大多數(shù)程序,特別是交互性的或其他事件驅(qū)動(dòng)(event-driven)的程序而言,為提前加載文件消耗資源是不劃算的。在實(shí)際訪問時(shí)分?jǐn)傢撜{(diào)入開銷才是更好的選擇。讓操作系統(tǒng)根據(jù)需要來調(diào)入頁意味著不訪問的頁永遠(yuǎn)不需要被加載。同預(yù)加載整個(gè)被映射的文件相比,這很容易減少 I/O 活動(dòng)總次數(shù)。操作系統(tǒng)已經(jīng)有一個(gè)復(fù)雜的內(nèi)存管理系統(tǒng)了,就讓它來替您完成此工作吧!
        我們可以通過調(diào)用isLoaded()方法來判斷一個(gè)被映射的文件是否完全常駐內(nèi)存了。如果該方法返回true值,那么很大概率是映射緩沖區(qū)的訪問延遲很少或者根本沒有延遲。不過,這也是不能保證的。同樣地,返回false值并不一定意味著訪問緩沖區(qū)將很慢或者該文件并未完全常駐內(nèi)存。isLoaded()方法的返回值只是一個(gè)暗示,由于垃圾收集的異步性質(zhì)、底層操作系統(tǒng)以及運(yùn)行系統(tǒng)的動(dòng)態(tài)性等因素,想要在任意時(shí)刻準(zhǔn)確判斷全部映射頁的狀態(tài)是不可能的。
        上面代碼中列出的最后一個(gè)方法force()同F(xiàn)ileChannel類中的同名方法相似(參見 3.3.1 節(jié))該方法會(huì)強(qiáng)制將映射緩沖區(qū)上的更改應(yīng)用到永久磁盤存儲(chǔ)器上。當(dāng)用MappedByteBuffer對(duì)象來更新一個(gè)文件,您應(yīng)該總是使用MappedByteBuffer.force()而非FileChannel.force(),因?yàn)橥ǖ缹?duì)象可能不清楚通過映射緩沖區(qū)做出的文件的全部更改。MappedByteBuffer沒有不更新文件元數(shù)據(jù)的選項(xiàng)——元數(shù)據(jù)總是會(huì)同時(shí)被更新的。請(qǐng)注意,非本地文件系統(tǒng)也同樣影響MappedByteBuffer.force()方法,正如它會(huì)對(duì)FileChannel.force()方法有影響,在這里(參見 3.3.1 節(jié))。
        如果映射是以MapMode.READ_ONLY或MAP_MODE.PRIVATE模式建立的,那么調(diào)用force()方法將不起任何作用,因?yàn)橛肋h(yuǎn)不會(huì)有更改需要應(yīng)用到磁盤上(但是這樣做也是沒有害處的)。例 3-4 詮釋了內(nèi)存映射緩沖區(qū)如何同scatter/gather結(jié)合使用。
        /*
        *例 3-4 使用映射文件和 gathering 寫操作來編寫 HTTP 回復(fù)
        */
        package com.ronsoft.books.nio.channels;
        import java.nio.ByteBuffer;
        import java.nio.MappedByteBuffer;
        import java.nio.channels.FileChannel;
        import java.nio.channels.FileChannel.MapMode;
        import java.nio.channels.GatheringByteChannel;
        import java.io.FileInputStream;
        import java.io.FileOutputStream;
        import java.io.IOException;
        import java.net.URLConnection;
        /**
        * Dummy HTTP server using MappedByteBuffers.
        * Given a filename on the command line, pretend to be
        * a web server and generate an HTTP response containing
        * the file content preceded by appropriate headers. The
        * data is sent with a gathering write.
        *
        * @author Ron Hitchens (ron@ronsoft.com)
        */
        public class MappedHttp {
        private static final String OUTPUT_FILE = "MappedHttp.out";
        private static final String LINE_SEP = "\r\n";
        private static final String SERVER_ID = "Server: Ronsoft Dummy Server";
        private static final String HTTP_HDR = "HTTP/1.0 200 OK" LINE_SEP SERVER_ID LINE_SEP;
        private static final String HTTP_404_HDR = "HTTP/1.0 404 Not Found" LINE_SEP SERVER_ID LINE_SEP;
        private static final String MSG_404 = "Could not open file: ";
        public static void main (String [] argv) throws Exception {
        if (argv.length < 1) {
        System.err.println ("Usage: filename");
        return;
        }
        String file = argv [0];
        ByteBuffer header = ByteBuffer.wrap(bytes (HTTP_HDR));
        ByteBuffer dynhdrs = ByteBuffer.allocate(128);
        ByteBuffer [] gather = { header, dynhdrs, null };
        String contentType = "unknown/unknown";
        long contentLength = -1;
        try {
        FileInputStream fis = new FileInputStream (file);
        FileChannel fc = fis.getChannel();
        MappedByteBuffer filedata =
        fc.map (MapMode.READ_ONLY, 0, fc.size());
        gather [2] = filedata;
        contentLength = fc.size();
        contentType = URLConnection.guessContentTypeFromName (file);
        } catch (IOException e) {
        // file could not be opened; report problem
        ByteBuffer buf = ByteBuffer.allocate (128);
        String msg = MSG_404 e LINE_SEP;
        buf.put (bytes (msg));
        buf.flip();
        // Use the HTTP error response
        gather [0] = ByteBuffer.wrap (bytes (HTTP_404_HDR));
        gather [2] = buf;
        contentLength = msg.length();
        contentType = "text/plain";
        }
        StringBuffer sb = new StringBuffer();
        sb.append ("Content-Length: " contentLength);
        sb.append (LINE_SEP);
        sb.append ("Content-Type: ").append (contentType);
        sb.append (LINE_SEP).append (LINE_SEP);
        dynhdrs.put (bytes (sb.toString()));
        dynhdrs.flip();
        FileOutputStream fos = new FileOutputStream (OUTPUT_FILE);
        FileChannel out = fos.getChannel();
        // All the buffers have been prepared; write 'em out
        while (out.write (gather) > 0) {
        // Empty body; loop until all buffers are empty
        }
        out.close();
        System.out.println ("output written to " OUTPUT_FILE);
        }
        // Convert a string to its constituent bytes
        // from the ASCII character set
        private static byte[] bytes(String string) throws Exception {
        return (string.getBytes ("US-ASCII"));
        }
        }
        例 3-5 詮釋了各種模式的內(nèi)存映射如何交互。具體來說,例中代碼詮釋了寫時(shí)拷貝是如何頁導(dǎo)向(page-oriented)的。當(dāng)在使用MAP_MODE.PRIVATE模式創(chuàng)建的MappedByteBuffer對(duì)象上調(diào)用put()方法而引發(fā)更改時(shí),就會(huì)生成一個(gè)受影響頁的拷貝。這份私有的拷貝不僅反映本地更改,而且使緩沖區(qū)免受來自外部對(duì)原來頁更改的影響。然而,對(duì)于被映射文件其他區(qū)域的更改還是可以看到的。
        /*
        *例 3-5 三種類型的內(nèi)存映射緩沖區(qū)
        */
        package com.ronsoft.books.nio.channels;
        import java.nio.ByteBuffer;
        import java.nio.MappedByteBuffer;
        import java.nio.channels.FileChannel;
        import java.io.File;
        import java.io.RandomAccessFile;
        /**
        * Test behavior of Memory mapped buffer types. Create a file, write
        * some data to it, then create three different types of mappings
        * to it. Observe the effects of changes through the buffer APIs
        * and updating the file directly. The data spans page boundaries
        * to illustrate the page-oriented nature of Copy-On-Write mappings.
        *
        * @author Ron Hitchens (ron@ronsoft.com)
        */
        public class MapFile {
        public static void main (String [] argv) throws Exception {
        // Create a temp file and get a channel connected to it
        File tempFile = File.createTempFile ("mmaptest", null);
        RandomAccessFile file = new RandomAccessFile (tempFile, "rw");
        FileChannel channel = file.getChannel();
        ByteBuffer temp = ByteBuffer.allocate (100);
        // Put something in the file, starting at location 0
        temp.put ("This is the file content".getBytes());
        temp.flip();
        channel.write (temp, 0);
        // Put something else in the file, starting at location 8192.
        // 8192 is 8 KB, almost certainly a different memory/FS page.
        // This may cause a file hole, depending on the
        // filesystem page size.
        temp.clear();
        temp.put ("This is more file content".getBytes());
        temp.flip();
        channel.write (temp, 8192);
        // Create three types of mappings to the same file
        MappedByteBuffer ro = channel.map (
        FileChannel.MapMode.READ_ONLY, 0, channel.size());
        MappedByteBuffer rw = channel.map (
        FileChannel.MapMode.READ_WRITE, 0, channel.size());
        MappedByteBuffer cow = channel.map (
        FileChannel.MapMode.PRIVATE, 0, channel.size());
        // the buffer states before any modifications
        System.out.println ("Begin");
        showBuffers (ro, rw, cow);
        // Modify the copy-on-write buffer
        cow.position (8);
        cow.put ("COW".getBytes());
        System.out.println ("Change to COW buffer");
        showBuffers (ro, rw, cow);
        // Modify the read/write buffer
        rw.position (9);
        rw.put (" R/W ".getBytes());
        rw.position (8194);
        rw.put (" R/W ".getBytes());
        rw.force();
        System.out.println ("Change to R/W buffer");
        showBuffers (ro, rw, cow);
        // Write to the file through the channel; hit both pages
        temp.clear();
        temp.put ("Channel write ".getBytes());
        temp.flip();
        channel.write (temp, 0);
        temp.rewind();
        channel.write (temp, 8202);
        System.out.println ("Write on channel");
        showBuffers (ro, rw, cow);
        // Modify the copy-on-write buffer again
        cow.position (8207);
        cow.put (" COW2 ".getBytes());
        System.out.println ("Second change to COW buffer");
        showBuffers (ro, rw, cow);
        // Modify the read/write buffer
        rw.position (0);
        rw.put (" R/W2 ".getBytes());
        rw.position (8210);
        rw.put (" R/W2 ".getBytes());
        rw.force();
        System.out.println ("Second change to R/W buffer");
        showBuffers (ro, rw, cow);
        // cleanup
        channel.close();
        file.close();
        tempFile.delete();
        }
        // Show the current content of the three buffers
        public static void showBuffers(ByteBuffer ro, ByteBuffer rw, ByteBuffer cow) throws Exception {
        dumpBuffer ("R/O", ro);
        dumpBuffer ("R/W", rw);
        dumpBuffer ("COW", cow);
        System.out.println ("");
        }
        // Dump buffer content, counting and skipping nulls
        public static void dumpBuffer (String prefix, ByteBuffer buffer) throws Exception {
        System.out.print (prefix ": '");
        int nulls = 0;
        int limit = buffer.limit();
        for (int i = 0; i < limit; i ) {
        char c = (char) buffer.get (i);
        if (c == '\u0000') {
        nulls ;
        continue;
        }
        if (nulls != 0) {
        System.out.print ("|[" nulls " nulls]|");
        nulls = 0;
        }
        System.out.print(c);
        }
        System.out.println ("'");
        }
        }
        以下是運(yùn)行上面程序的輸出:
        BeginR/O: 'This is the file content|[8168 nulls]|This is more file content'R/W: 'This is the file content|[8168 nulls]|This is more file content'COW: 'This is the file content|[8168 nulls]|This is more file content'Change to COW bufferR/O: 'This is the file content|[8168 nulls]|This is more file content'R/W: 'This is the file content|[8168 nulls]|This is more file content'COW: 'This is COW file content|[8168 nulls]|This is more file content'Change to R/W bufferR/O: 'This is t R/W le content|[8168 nulls]|Th R/W more file content'R/W: 'This is t R/W le content|[8168 nulls]|Th R/W more file content'COW: 'This is COW file content|[8168 nulls]|Th R/W more file content'Write on channelR/O: 'Channel write le content|[8168 nulls]|Th R/W moChannel write t'R/W: 'Channel write le content|[8168 nulls]|Th R/W moChannel write t'COW: 'This is COW file content|[8168 nulls]|Th R/W moChannel write t'Second change to COW bufferR/O: 'Channel write le content|[8168 nulls]|Th R/W moChannel write t'R/W: 'Channel write le content|[8168 nulls]|Th R/W moChannel write t'COW: 'This is COW file content|[8168 nulls]|Th R/W moChann COW2 te t'Second change to R/W bufferR/O: ' R/W2 l write le content|[8168 nulls]|Th R/W moChannel R/W2 t'R/W: ' R/W2 l write le content|[8168 nulls]|Th R/W moChannel R/W2 t'COW: 'This is COW file content|[8168 nulls]|Th R/W moChann COW2 te t'
        Java nio入門教程詳解(二十二)
        00
        我們認(rèn)為:用戶的主要目的,是為了獲取有用的信息,而不是來點(diǎn)擊廣告的。因此本站將竭力做好內(nèi)容,并將廣告和內(nèi)容進(jìn)行分離,確保所有廣告不會(huì)影響到用戶的正常閱讀體驗(yàn)。用戶僅憑個(gè)人意愿和興趣愛好點(diǎn)擊廣告。
        我們堅(jiān)信:只有給用戶帶來價(jià)值,用戶才會(huì)給我們以回報(bào)。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多