byterat

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            54 隨筆 :: 0 文章 :: 15 評(píng)論 :: 0 Trackbacks

          緩沖區(qū)基礎(chǔ)

          抽象類Buffer是java.nio包支持緩沖區(qū)的基礎(chǔ)。 Buffer 的工作方式就象內(nèi)存中用于讀寫(xiě)基本數(shù)據(jù)類型的 RandomAccessFile 。象 RandomAccessFile 一樣,使用 Buffer ,所執(zhí)行的下一個(gè)操作(讀/寫(xiě))在當(dāng)前某個(gè)位置發(fā)生。執(zhí)行讀/寫(xiě)操作中的任一個(gè)都會(huì)改變那個(gè)位置,所以在寫(xiě)操作之后進(jìn)行讀操作不會(huì)讀到剛才所寫(xiě)的內(nèi)容,而會(huì)讀到剛才所寫(xiě)內(nèi)容之后的數(shù)據(jù)。 Buffer 提供了四個(gè)指示方法,用于訪問(wèn)線性結(jié)構(gòu)(從最高值到最低值):

          capacity() :表明緩沖區(qū)的容量大小, 一旦確定了大小, 將不能再改變;
          limit() :告訴您到目前為止已經(jīng)往緩沖區(qū)填了多少字節(jié),或者讓您用 :limit(int newLimit) 來(lái)改變這個(gè)限制
          position() :告訴您當(dāng)前的位置,以執(zhí)行下一個(gè)讀/寫(xiě)操作
          mark() :為了稍后用 reset() 進(jìn)行重新設(shè)置而記住某個(gè)位置
          flip() :交換限制指針和位置指針,然后將位置置為 0,并廢棄已經(jīng)做的mark標(biāo)記

          緩沖區(qū)的基本操作是讀 get() 和寫(xiě) put() ;然而,這些方法在子類中都是針對(duì)每種數(shù)據(jù)類型的特定方法。為了說(shuō)明這一情況,讓我們研究一個(gè)簡(jiǎn)單示例,該示例演示了從同一個(gè)緩沖區(qū)讀和寫(xiě)一個(gè)字符。在清單 1 中, flip() 方法交換限制和位置,然后將位置置為 0,并廢棄標(biāo)記,讓您讀剛才所寫(xiě)的數(shù)據(jù):


          清單 1. 讀/寫(xiě)示例
          import java.nio.*;
          ...
          CharBuffer buff = ...;
          buff.put('A');
          buff.flip();
          char c = buff.get();
          System.out.println("An A: " + c);
           


          現(xiàn)在讓我們研究一些具體的 Buffer 子類。

           

          緩沖區(qū)類型

          Merlin 具有 7 種特定的 Buffer 類型,每種類型對(duì)應(yīng)著一個(gè)基本數(shù)據(jù)類型(不包括 boolean):

          ByteBuffer       //存放任何除boolean類型外的其他基本類型
          CharBuffer       //存放char
          DoubleBuffer     //存放double
          FloatBuffer      //存放float
          IntBuffer        //存放int
          LongBuffer       //存放long
          ShortBuffer      //存放short

          在本文后面,我將討論第 8 種類型 MappedByteBuffer ,它用于內(nèi)存映射文件。如果您必須使用的類型不是這些基本類型,則可以先從 ByteBuffer 獲得字節(jié)類型,然后將其轉(zhuǎn)換成 Object 或其它任何類型。


          創(chuàng)建緩沖區(qū)
          一共有兩種類型的緩沖區(qū),直接緩沖區(qū)和非直接緩沖區(qū)。

          在創(chuàng)建緩沖區(qū)時(shí),可以要求創(chuàng)建直接緩沖區(qū),創(chuàng)建直接緩沖區(qū)的成本要比創(chuàng)建間接緩沖區(qū)高,但這可以使運(yùn)行時(shí)環(huán)境直接在該緩沖區(qū)上進(jìn)行較快的本機(jī) I/O 操作。因?yàn)閯?chuàng)建直接緩沖區(qū)所增加的成本,所以直接緩沖區(qū)只用于長(zhǎng)生存期的緩沖區(qū),而不用于短生存期、一次性且用完就丟棄的緩沖區(qū)。而且,只能在 ByteBuffer 這個(gè)級(jí)別上創(chuàng)建直接緩沖區(qū),如果希望使用其它類型,則必須將 Buffer 轉(zhuǎn)換成更具體的類型。

          判斷一個(gè)緩沖區(qū)是否是直接緩沖區(qū),可以調(diào)用isDirect()方法。

          有三種方式來(lái)獲取一個(gè)緩沖區(qū)的對(duì)象:
          a. 調(diào)用allocate()或者allocateDirect()方法直接分配,其中allocateDirect()返回的是直接緩沖區(qū)。
          b. 包裝一個(gè)數(shù)組,如:
                byte[] b = new byte[1024];
                ByteBuffer bb = ByteBuffer.wrap(b);
          c. 內(nèi)存映射,即調(diào)用FileChannel的map()方法。

          緩沖區(qū)基本屬性
          這幾個(gè)屬性是每個(gè)緩沖區(qū)都有的并且是常用的操作。
          a. 容量(capacity),緩沖區(qū)大小
          b. 限制(limit),第一個(gè)不應(yīng)被讀取或?qū)懭氲淖止?jié)的索引,總是小于容量。
          c. 位置(position),下一個(gè)被讀取或?qū)懭氲淖止?jié)的索引,總是小于限制。
          d. clear()方法:設(shè)置limit為capacity,position為0。
          e. filp()方法:設(shè)置limit為當(dāng)前position,然后設(shè)置position為0。
          f. rewind()方法:保持limit不變,設(shè)置position為0。

          緩沖區(qū)數(shù)據(jù)操作
          操作包括了讀取和寫(xiě)入數(shù)據(jù)兩種。
          讀取數(shù)據(jù)使用get()及其系列方法,除boolean外,每一種類型包括了對(duì)應(yīng)的get()方法,如getInt(),getChar()等,get()方法用來(lái)讀取字節(jié),支持相對(duì)和絕對(duì)索引兩種方式。
          寫(xiě)入數(shù)據(jù)使用put()及其系列方法,和get()方法是對(duì)應(yīng)的。

          package nio;

          import java.io.FileInputStream;
          import java.io.FileOutputStream;
          import java.nio.ByteBuffer;
          import java.nio.channels.FileChannel;

          public class BufferDemo ...{

              
              public static void main(String[] args) throws Exception...{
                  //分配一個(gè)非直接緩沖區(qū)
                  ByteBuffer bb = ByteBuffer.allocate(100);
                  //向緩沖區(qū)寫(xiě)入0到100的字節(jié)制
                  for(int i = 0; i <100; i++)...{
                      byte b = (byte) (Math.random() * 100);
                      bb.put(b);
                  }
                  
                  System.out.println("寫(xiě)入文件前的緩沖區(qū)數(shù)據(jù)");
                  bb.flip();
                  while(bb.hasRemaining())
                      System.out.print(bb.get() + " ");
                  System.out.println();
                  
                  //獲取一個(gè)關(guān)聯(lián)到文件buffer.txt的信道
                  FileChannel fc = new FileOutputStream("buffer.txt").getChannel();
                  //將緩沖區(qū)數(shù)據(jù)寫(xiě)到文件中
                  bb.flip();
                  fc.write(bb);
                  //防止緩存
                  fc.force(true);
                  //關(guān)閉信道
                  fc.close();
                  bb = null;
                  fc = null;
                  
                  //下面從文件中讀取數(shù)據(jù)
                  fc = new FileInputStream("buffer.txt").getChannel();
                  ByteBuffer bb2 = ByteBuffer.allocate((int) fc.size());
                  fc.read(bb2);
                  System.out.println("從文件讀取的緩沖區(qū)數(shù)據(jù)");
                  bb2.flip();
                  while(bb2.hasRemaining())
                      System.out.print(bb2.get() + " ");
                  System.out.println();
                  fc.close();
                  bb2 = null;
                  fc = null;
                  

              }

          }

          內(nèi)存映射文件

          第 8 種 Buffer 類型 MappedByteBuffer 只是一種特殊的 ByteBuffer 。 MappedByteBuffer 將文件所在區(qū)域直接映射到內(nèi)存。通常,該區(qū)域包含整個(gè)文件,但也可以只映射部分文件。所以,必須指定要映射文件的哪部分。而且,與其它 Buffer 對(duì)象一樣,這里沒(méi)有構(gòu)造函數(shù);必須讓 java.nio.channels.FileChannel 的 map() 方法來(lái)獲取 MappedByteBuffer 。此外,無(wú)需過(guò)多涉及通道就可以用 getChannel() 方法從 FileInputStream 或 FileOutputStream 獲取 FileChannel 。通過(guò)從命令行傳入文件名來(lái)讀取文本文件的內(nèi)容,清單 4 顯示了 MappedByteBuffer :


          清單 4. 讀取內(nèi)存映射文本文件
          import java.io.*;
          import java.nio.*;
          import java.nio.channels.*;
          import java.nio.charset.*;
          public class ReadFileBuff {
            public static void main(String args[]) throws IOException {
               if (args.length != 0) {
                String filename = args[0];
                FileInputStream fis = new FileInputStream(filename);
                FileChannel channel = fis.getChannel();
                int length = (int)channel.size();
                MappedByteBuffer byteBuffer =
                  channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
                Charset charset = Charset.forName("ISO-8859-1");
                CharsetDecoder decoder = charset.newDecoder();
                CharBuffer charBuffer = decoder.decode(byteBuffer);
                for (int i=0, n=charBuffer.length(); i<n; i++) {
                  System.out.print(charBuffer.get());
                }
              }
            }
          }

          posted on 2007-08-01 11:13 比特鼠 閱讀(3829) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 新闻| 新安县| 富阳市| 安仁县| 张家港市| 东海县| 莎车县| 溧水县| 建水县| 墨江| 怀柔区| 临江市| 宁城县| 陈巴尔虎旗| 湘潭市| 长丰县| 行唐县| 宝兴县| 瑞金市| 宝山区| 海晏县| 贞丰县| 永定县| 台湾省| 玉门市| 铜陵市| 大厂| 光泽县| 白玉县| 乌兰浩特市| 陕西省| 林口县| 三门峡市| 永寿县| 翁牛特旗| 灵璧县| 海南省| 南宁市| 水城县| 康定县| 江永县|