隨筆 - 312, 文章 - 14, 評論 - 1393, 引用 - 0
          數據加載中……

          Java網絡編程從入門到精通(34):讀寫緩沖區中的數據---使用get和put方法按順序讀寫單個數據

          本文為原創,如需轉載,請注明作者和出處,謝謝!

          上一篇:Java網絡編程從入門到精通(33):非阻塞I/O的緩沖區(Buffer)

              對于緩沖區來說,最重要的操作就是讀寫操作。緩沖區提供了兩種方法來讀寫緩沖區中的數據:get、put方法和array方法。而getput方法可以有三種讀寫數據的方式:按順序讀寫單個數據、在指定位置讀寫單個數據和讀寫數據塊。除了上述的幾種讀寫數據的方法外,CharBuffer類還提供了用于專門寫字符串的putappend方法。在本文及后面的文章中將分別介紹這些讀寫緩沖區的方法。

          雖然使用allocate方法創建的緩沖區并不是一次性地分配內存空間,但我們可以從用戶地角度將一個緩沖區想象成一個長度為capacity的數組。當緩沖區創建后,和數組一樣,緩沖區的大小(capacity值)將無法改變,也無法訪問緩沖區外的數據。如下面的代碼創建了一個大小為6的字節緩沖區。

          ByteBuffer byteBuffer = ByteBuffer.allocate(6);

          對于byteBuffer來說,只能訪問屬于這個緩沖區的六個字節的數據,如果超過了這個范圍,將拋出一個BufferOverflowException異常,這是一個運行時錯誤,因為這個錯誤只能在程序運行時被發現。

          既然緩沖區和數組類似,那么緩沖區也應該象數組一樣可以標識當前的位置。緩沖區的position方法為我們提供了這個功能。position方法有兩種重載形式,它們的定義如下:

          public final int position()
          public final Buffer position(int newPosition)

          第一個重載形式用來獲取緩沖區的當前位置。在創建緩沖區后,position的初始值是0,也就是緩沖區第一個元素的位置。當從緩沖區讀取一個元素后,position的值加1。我們從這一點可以看出,position方法返回的位置就是當前可以讀取的元素的位置。position的取值范圍從0capacity – 1。如果position的值等于capacity,說明緩沖區當前已經沒有數據可讀了。

          position方法的第二個重載形式可以設置緩沖區的當前位置。參數newPosition的取值范圍是0 <= newPosition < capacity。如果newPosition的值超出這個范圍,position方法就會拋出一個IllegalArgumentException異常。

          在大多數情況下不需要直接控制緩沖區的位置。緩沖區類提供的用于讀寫數據的方法可以自動地設置緩沖區的當前位置。在緩沖區類中,getput方法用于讀寫緩沖區中的數據。getput方法的定義如下:

          ByteBuffer類的getput方法:

          public abstract byte get()            
          public abstract ByteBuffer put(byte b)

          IntBuffer類的getput方法:

          public abstract int get()            
          public abstract IntBuffer put(int i)

          其他五個緩沖區類中的getput方法定義和上面的定義類似,只是get方法返回相應的數據類型,而put方法的參數是相應的數據類型,并且返回值的類型是相應的緩沖區類。

          每當put方法向緩沖區寫入一個數據后,緩沖區的當前位置都會加1。如果緩沖區的當前位置已經等于capacity,調用put方法就會拋出一個java.nio.BufferOverflowException異常。在緩沖區未初賦值的區域將被0填充。使用get方法可以得到緩沖區當前位置的數據,并使緩沖區的當前位置加1。和put方法一樣,在緩沖區當前位置等于capacity時使用get方法也會拋出java.nio.BufferOverflowException異常。緩沖區的初始狀態如圖1所示。

          圖1 緩沖區的初始狀態

          從圖1可以看出,在緩沖區創建之初,當前的位置和緩沖區中的數據都為0。當使用如下語句向緩沖區中寫入數據后,緩沖區當前狀態如圖2所示。

           

          byteBuffer.put((byte)2);
          byteBuffer.put((
          byte)-1);

          圖2  緩沖區的當前狀態

           

          當緩沖區的當前位置如圖3所示時,使用putget方法將會拋出上述的BufferOverflowException異常。

          圖3  當前位置處于緩沖區尾

          如果要使用get方法得到緩沖區中的指定數據,必須將緩沖區的當前位置移動到指定的位置,我們可以使用position方法將當前位置移到緩沖區的任何位置。如下面的代碼將圖3所示的緩沖區的當前位置設為2,并用get方法獲得位置2的數據:

          byteBuffer.position(2);
          System.out.println(byteBuffer.get());

          上面的代碼將輸出3。緩沖區的當前位置為除了使用position方法,也可以使用rewind方法將緩沖區的當前位置設為0rewind方法的定義如下:

          public final Buffer rewind()

          在圖2所示的緩沖區狀態下調用rewind方法,就會得到如圖4的緩沖區狀態。

          圖4  調用rewind方法后的緩沖區狀態

          接下來讓我們執行如下語句:

          System.out.println(byteBuffer.get());

          緩沖區的狀態將如圖5所示。

          圖5  調用get方法后的緩沖區狀態

          緩沖區除了positioncapacity外,還提供了一個標識來限制緩沖區可訪問的范圍。這個標識就是limitlimitposition一樣,在緩沖區類中也提供了兩個重載方法。用于獲得和設置limit的值。limit方法的定義如下:


          public final int limit()
          public final Buffer limit(int newLimit)

          在初始狀態下,緩沖區的limitcapacity值相同。但limitcapacity的區別是limit可以通過limit方法進行設置,而capacity在創建緩沖區時就已經指定了,并且不能改變。(在上面所講的position方法的newPosition參數的取值范圍時曾說是0 <= newPosition < capacity,其實嚴格地說,應是0 <= newPosition < limitlimit的其他性質和capacity一樣。如在圖5所示的緩沖區狀態中將limit的值設為2,就變成了圖6所示的狀態。

          圖6  將limit設為2的緩沖區狀態

          在這時position的值等于limit,就不能訪問緩沖區的當前數據,也就是說不能使用getput方法。否則將拋出BufferOverflowException異常。由于使用allocate創建的緩沖區并不是一次性地分配內存空間,因此,可以將緩沖區的capacity設為很大的值,如10M。緩沖區過大可能在某些環境中會使系統性能降低(如在PDA或智能插秧機中),因此,可以使用limit方法根據具體的情況來限定緩沖區的大小。當然,limit還可以表示緩沖區中實際的數據量,這將在后面講解。下面的代碼演示了如何使用limit方法來枚舉緩沖區中的數據:

          while(byteBuffer.position() < byteBuffer.limit())
              System.out.println(byteBuffer.get());

          我們還可以用fliphasRemaining方法來重寫上面的代碼。flip方法將limit設為緩沖區的當前位置。當limit等于position時,hasRemaining方法返回false,而則返回true fliphasRemaining方法的定義如下:


          public final Buffer flip()
          public final boolean hasRemaining()

              下面的代碼演示了如何使用hasRemaining方法來枚舉緩沖區中的數據:

          while(byteBuffer.hasRemaining())
              System.out.println(byteBuffer.get());

          如果從緩沖區的第一個位置依次使用put方法向緩沖區寫數據,當寫完數據后,再使用flip方法。這樣limit的值就等于緩沖區中實際的數據量了。在網絡中傳遞數據時,可以使用這種方法來設置數據的結束位置。

          為了回顧上面所講內容,下面的代碼總結了創建緩沖區、讀寫緩沖區中的數據、設置緩沖區的limitposition的方法。

            package net;
            
            
          import java.nio.*;
            
            
          public class GetPutData
            {
                
          public static void main(String[] args)
                {
                    
          // 創建緩沖區的四種方式
                    IntBuffer intBuffer = IntBuffer.allocate(10);
                    ByteBuffer byteBuffer 
          = ByteBuffer.allocateDirect(10);
                    CharBuffer charBuffer 
          = CharBuffer.wrap("abcdefg");
                    DoubleBuffer doubleBuffer 
          = DoubleBuffer.wrap(new double[] { 1.12.2 });
                    
                    
          // 向緩沖區中寫入數據
                    intBuffer.put(1000);
                    intBuffer.put(
          2000);
                    
                    System.out.println(
          "intBuffer的當前位置:" + intBuffer.position());
                    
                    intBuffer.position(
          1);  // 將緩沖區的當前位置設為1
                    System.out.println(intBuffer.get());  // 輸出緩沖區的當前數據
                    
                    intBuffer.rewind();  
          // 將緩沖區的當前位置設為0
                    System.out.println(intBuffer.get());  // 輸出緩沖區的當前數據
                    
                    byteBuffer.put((
          byte)20);
                    byteBuffer.put((
          byte)33);
                    byteBuffer.flip();   
          // 將limit設為position,在這里是2
                    byteBuffer.rewind(); 
                    
          while(byteBuffer.hasRemaining())  // 枚舉byteBuffer中的數據
                        System.out.print(byteBuffer.get() + " ");
                    
                    
          while(charBuffer.hasRemaining())  // 枚舉charBuffer中的數據
                        System.out.print(charBuffer.get() + " ");
            
                    
          // 枚舉doubleBuffer中的數據
                    while(doubleBuffer.position() < doubleBuffer.limit())
                        System.out.print(doubleBuffer.get() 
          + " ");
            
                }
            }

          運行結果:  

          intBuffer的當前位置:2
          2000
          1000
          20 33 a b c d e f g 1.1 2.2

          注意:如果必須使用緩沖區的大小來讀取緩沖區的數據,盡量不要使用capacity,而要使用limit。如盡量不要寫成如下的代碼:

          while(byteBuffer.position() < byteBuffer.capacity())
              System.out.println(byteBuffer.get());

          這是因為當limit比capacity小時,上面的代碼將會拋出一個BufferUnderflowException異常。





          Android開發完全講義(第2版)(本書版權已輸出到臺灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2009-10-09 09:34 銀河使者 閱讀(4882) 評論(1)  編輯  收藏 所屬分類: java 、 原創 、網絡編程

          評論

          # re: Java網絡編程從入門到精通(34):讀寫緩沖區中的數據---使用get和put方法按順序讀寫單個數據  回復  更多評論   

          講的真不錯,不知道有沒有的更新了
          2010-06-05 20:07 | 菜鳥學習
          主站蜘蛛池模板: 鹰潭市| 蓬安县| 军事| 宁夏| 朝阳区| 塘沽区| 宁都县| 楚雄市| 大庆市| 武冈市| 泗水县| 潜江市| 阳高县| 平顺县| 丹东市| 永清县| 平罗县| 清水县| 新和县| 叙永县| 繁昌县| 江都市| 玛沁县| 昆明市| 榆树市| 贡嘎县| 六盘水市| 新安县| 方正县| 静宁县| 衢州市| 通海县| 嘉定区| 武穴市| 固阳县| 章丘市| 张家界市| 诸暨市| 安吉县| 东台市| 华蓥市|