<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 40, comments - 58, trackbacks - 0, articles - 0
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    對 java.nio.ByteBuffer 的理解

    Posted on 2011-05-18 10:53 Astro.Qi 閱讀(417) 評論(4)  編輯  收藏 所屬分類: Java

    今晚用到 ByteBuffer, 我跟 joy 都是初學 java, 文檔里的中文翻譯實在是看他母親不懂, 暈了半天, 作了幾個測試, 終于把這個類的用法搞清楚了, 順便臆想了哈其工作原理.

    先列點代碼片段:
    // ...
    //
    // 此段代碼功能為從 t.txt 里復制所有數(shù)據(jù)到 out_j.txt:
    //
    ...
    1 FileChannel fcin = new FileInputStream( "d:/t.txt" ).getChannel();
    2 FileChannel fcout = new FileOutputStream( new File( "d:/out_j.txt" )).getChannel();
    3 ByteBuffer buff = ByteBuffer.allocate( 1024 );
    4 long t1 = System.currentTimeMillis();
    5
    6 while( fcin.read( buff ) != -1 )
    7 {
    8   buff.flip();
    9   fcout.write( buff );
    10   buff.clear();
    11 }
    12
    13 long t2 = System.currentTimeMillis();
    14 long size = fcin.size();
    15 javax.swing.JOptionPane.showMessageDialog( null, size + " 字節(jié), 耗時 " + ( t2 - t1 + 1 ) + " ms." );
    ...

    ----------------------------------------------------------------------------------------------------

    SDK 文檔里對 ByteBuffer 的說明為:

    public abstract class ByteBuffer
    extends Buffer
    implements Comparable <ByteBuffer>

    這說明 ByteBuffer 是繼承于 Buffer 的抽象類, 實現(xiàn)了兩個接口.

    行3 通過 allocate() 分配了一塊 1024 字節(jié)的緩沖區(qū), 并返回一個 ByteBuffer 對象. (抽象類不能直接 new)
    行6 fcin.read() 將數(shù)據(jù)讀入到 buff. 此處的 read() 是 FileChannel 類的一個虛函數(shù).
    行8 buff.flip() 這個調(diào)用就是開頭一直無法理解的部分.

    ----------------------------------------------------------------------------------------------------

    SDK 文檔里的對 flip() 的說明是:

    public final Buffer flip()
    反轉此緩沖區(qū)。首先對當前位置設置限制,然后將該位置設置為零。如果已定義了標記,則丟棄該標記。
    當將數(shù)據(jù)從一個地方傳輸?shù)搅硪粋€地方時,經(jīng)常將此方法與 compact 方法一起使用。

    我最終的理解是: 文檔翻譯得太差了, 把不應該翻譯的內(nèi)容也譯成了中文, 所以反而不容易理解.
    關鍵就在以下 2 處:

    當前位置: 這個可以直觀地理解為緩沖區(qū)中的當前數(shù)據(jù)指針, 或是 SQL 中的游標, 記為 curPointer.
    限制: 這個可以理解成實際操作的緩沖區(qū)段的結束標記, 記為 endPointer.
    反轉: 這個完全是對 flip 這個詞不負責的翻譯, 如果參照 DirectX 里的 flip() 而譯為翻轉/翻頁, 那就好理解得多, 就像寫信/看信, 寫/看完一頁后, 翻到下一頁, 眼睛/筆從頁底重新移回頁首.
    這個翻轉背后的操作其實就是 "把 endPointer 定位到 curPointer 處, 并把 curPointer 設為 0".

    關于標記, 在這里不涉及. 下一句說到常與 compact 方法一起使用, 是可以想像的, 因為 compact 方法對數(shù)據(jù)進
    行了壓縮, 有效數(shù)據(jù)的真實長度發(fā)生了變化, 肯定需要用 flip 重新定位結束標記.

    在填充, 壓縮等數(shù)據(jù)操作時, curPointer 估計都是自動更新了位置的, 總是指向最后一個有效數(shù)據(jù), 所以每次調(diào)
    用 flip() 后, endPointer 就指向了有效數(shù)據(jù)的結尾, 而 curPointer 指向了 0 (緩沖起始處).

    舉個圖例:
    (c 和 e 分別代表 curPointer 和 endPointer 兩個指針)

    * 先是一個空的 ByteBuffer (大小為 10 字節(jié))
    -------------------
    -------------------
    c
    e


    * 然后填充 5 字節(jié)數(shù)據(jù)
    -------------------
    0 1 2 3 4
    -------------------
    e           c
    此時, endPointer 尚在 0 處, curPointer 移到了數(shù)據(jù)結尾.
    經(jīng)測試, 此時若取數(shù)據(jù), 將得到 5 個字節(jié), 內(nèi)容通常為 0 (也有可能是未知), 因為實際上取到的是從 c 處到緩沖
    區(qū)實際結束處的 5 個未初始化的字節(jié).

    * 調(diào)用一次 flip() 后
    -------------------
    0 1 2 3 4
    -------------------
    c           e
    此時, endPointer 先被移到 curPointer, 然后 curPointer 移到 0.
    通過測試可見, ByteBuffer 取數(shù)據(jù)時, 是從 curPointer 起, 到 endPointer 止, 若 curPointer > endPointer, 則取到緩沖區(qū)結束.


    再看上面代碼的關鍵片段, 行 8 處調(diào)用 flip() 即有兩個作用, 一是將 curPointer 移到 0, 二是將 endPointer 移到有效數(shù)據(jù)結尾.

    此行可由以下兩行代替:
    buff.limit( buff.position());
    buff.position( 0 );

    可見對其工作原理的理解, 應該是正確的.

    ----------------------------------------------------------------------------------------------------

    總結如下:
    1. put 數(shù)據(jù)時, 不會自動清除緩沖區(qū)中現(xiàn)有的數(shù)據(jù).
    2. 每一次 get 或 put 后, curPointer 都將向緩沖區(qū)尾部移動, 移動量=操作的數(shù)據(jù)量.
    3. get/put 均是從 curPointer 起, 到 curPointer + 操作的數(shù)據(jù)長度止.
    4. get/put 操作中, 若 curPointer 超過了 endPointer 或緩沖區(qū)總長度, 將拋出 java.nio.BufferUnderflowException 異常.

    注: curPointer 和 endPointer 只是為文中方便描述命名的, 實際分別對應到 ByteBuffer.position() 和 ByteBuffer.limit() 兩個方法.

    ----------------------------------------------------------------------------------------------------

    疑惑:
    curPointer 是用 ByteBuffer.position() 取值, 用 ByteBuffer.position( int ) 賦值, 不知道 JDK 為什么要用多態(tài)來實現(xiàn)這兩個功能, 按我的想法, 設計成 getPosition(), setPosition() 不是要好看好記得多啊.

    ----------------------------------------------------------------------------------------------------

    跟 C++ 的簡單比較:
    C++ 里面沒有類似 ByteBuffer 的現(xiàn)成實現(xiàn), 實現(xiàn)上述類似的文件復制功能, 通常要自己創(chuàng)建管理緩沖區(qū). C++ 里讀寫文件通常用 FileRead(), FileWrite() 函數(shù), 在讀/寫的時候, 可以直接指定讀/寫的數(shù)據(jù)長度, 相比下顯得
    直觀方便些, 但 JDK 這個 ByteBuffer 的方式, 確實更方便好用.

    ByteBuffer 作為繼承自 Buffer 的抽象類, 實現(xiàn)了對 Byte 型緩沖的管理, 同時 JDK 里還有對應其他數(shù)據(jù)類型的
    繼承自 Buffer 的抽象類, 分別實現(xiàn)對應類型的緩沖管理. 這種設計減少了編程時的工作. 如果在 C++ 中, 調(diào)用
    讀/寫函數(shù)時, 還需要考慮傳入數(shù)據(jù)的類型, 通常用傳入 sizeof(數(shù)據(jù)類型) 的方式指定, 除了函數(shù)調(diào)用時增加耗
    費外, 靈活性也更差些.

    反過來再想, 為什么 C 要用這種方式? 個人認為, 這是 C 標準庫的實現(xiàn)方式, 因為在不同 OS 平臺上, 對文件和
    設備的訪問方法在系統(tǒng)層不一定相同, 同時硬件平臺(主要是 CPU)上基本數(shù)據(jù)類型寬度也有可能不同, 標準庫通過
    sizeof 這個宏在編譯時才能確定數(shù)據(jù)寬度, 所以標準 C 代碼通常可以在不同平臺上重新編譯.

    再想 C++ 為什么要用這種方式? 首先, C++ 里沿用 C 標準庫的模式是可以理解的, 其次, 也許只是 C++ 標準庫
    里沒有類似的設計, 說不定早就有第三方通過模板實現(xiàn)的了.

    個人認為, ByteBuffer 在實現(xiàn)上, 可以算是一種數(shù)據(jù)結構, 在類設計上, 可以算是一種設計模式了.

    評論

    # re: 對 java.nio.ByteBuffer 的理解[未登錄]  回復  更多評論   

    2014-04-07 11:21 by 1
    1

    # re: 對 java.nio.ByteBuffer 的理解[未登錄]  回復  更多評論   

    2014-04-07 11:21 by 1
    11

    # re: 對 java.nio.ByteBuffer 的理解[未登錄]  回復  更多評論   

    2014-04-07 11:21 by 1
    1

    # re: 對 java.nio.ByteBuffer 的理解[未登錄]  回復  更多評論   

    2014-04-07 11:22 by 1
    12
    主站蜘蛛池模板: 国产男女性潮高清免费网站 | 免费在线观看的网站| 亚洲色精品88色婷婷七月丁香| 噜噜综合亚洲AV中文无码| 日本人护士免费xxxx视频| 亚洲精品人成网线在线播放va| 免费精品国产日韩热久久| 91亚洲性爱在线视频| 青娱乐免费在线视频| wwwxxx亚洲| 午夜老司机免费视频| 国产精品亚洲专区无码牛牛| 香蕉高清免费永久在线视频| 国产精品亚洲专区无码唯爱网| 免费人成在线观看视频播放| 人体大胆做受免费视频| 国产av无码专区亚洲av果冻传媒| aaa毛片视频免费观看| 久久精品国产亚洲AV无码麻豆 | **俄罗斯毛片免费| 亚洲国产成+人+综合| 免费A级毛片无码无遮挡内射| 亚洲 日韩经典 中文字幕| 国产成人高清精品免费软件| 一级中文字幕免费乱码专区| 亚洲欧洲日产国码无码久久99| 免费人成在线观看网站| 亚洲AV无码专区在线亚| 国产免费观看青青草原网站| 一级一级一级毛片免费毛片| 亚洲国产成人精品不卡青青草原| 久久久久亚洲Av无码专| 国产91色综合久久免费分享| 国产精品久久久久久亚洲小说 | 亚洲一欧洲中文字幕在线| 免费视频中文字幕| 91视频免费观看高清观看完整| 亚洲精品影院久久久久久| 国产人妖ts在线观看免费视频| 岛国岛国免费V片在线观看| 国产一区二区三区在线免费|