溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java Buffer緩沖區(NIO)操作簡介

發布時間:2021-09-13 11:25:13 來源:億速云 閱讀:605 作者:chen 欄目:開發技術

這篇文章主要講解了“Java Buffer緩沖區(NIO)操作簡介”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Java Buffer緩沖區(NIO)操作簡介”吧!

目錄
  • Java NIO(Buffer)

    • 1.1 Buffer 簡介

    • 1.2 Buffer 的基本用法

      • 1、使用 Buffer 讀寫數據,一般遵循以下四個步驟:

      • 2、使用 ByteBuffer的例子

      • 3、使用 IntBuffer 的例子

    • 1.3 Buffer 的 capacity、position 和 limit

      • (1)capacity

      • (2)position

      • (3)limit

    • 1.4 Buffer 的類型

      • 1.5 Buffer 分配和寫數據

        • 1、Buffer 分配

        • 2、向 Buffer 中寫數據

        • 3、flip()方法

      • 1.6 從 Buffer 中讀取數據

        • 1.7 Buffer 幾個方法

          • 1、rewind()方法

          • 2、clear()與 compact()方法

          • 3、mark()與 reset()方法

        • 1.8、緩沖區操作

          • 1、緩沖區分片

          • 2、只讀緩沖區

          • 3、直接緩沖區

          • 4、內存映射文件 I/O

      Java NIO(Buffer)

      1.1 Buffer 簡介

      Java NIO 中的 Buffer 用于和 NIO 通道進行交互。數據是從通道讀入緩沖區,從緩沖區寫入到通道中的。

      Java Buffer緩沖區(NIO)操作簡介

      緩沖區本質上是一塊可以寫入數據,然后可以從中讀取數據的內存。這塊內存被包裝成 NIO Buffer 對象,并提供了一組方法,用來方便的訪問該塊內存。

      緩沖區實際上是一個容器對象,更直接的說,其實就是一個數組,在 NIO 庫中,所有數據都是用緩沖區處理的。

      在讀取數據時,它是直接讀到緩沖區中的; 在寫入數據時,它也是寫入到緩沖區中的;任何時候訪問 NIO 中的數據,都是將它放到緩沖區中。而在面向流 I/O系統中,所有數據都是直接寫入或者直接將數據讀取到 Stream 對象中。

      在 NIO 中,所有的緩沖區類型都繼承于抽象類 Buffer,最常用的就是 ByteBuffer,對于 Java 中的基本類型,基本都有一個具體 Buffer 類型與之相對應,它們之間的繼承關系如下圖所示:

      Java Buffer緩沖區(NIO)操作簡介

      1.2 Buffer 的基本用法

      1、使用 Buffer 讀寫數據,一般遵循以下四個步驟:

      (1)寫入數據到 Buffer

      (2)調用 flip()方法

      (3)從 Buffer 中讀取數據

      (4)調用 clear()方法或者 compact()方法

      當向 buffer 寫入數據時,buffer 會記錄下寫了多少數據。一旦要讀取數據,需要通過flip()方法將 Buffer 從寫模式切換到讀模式。

      在讀模式下,可以讀取之前寫入到 buffer的所有數據。一旦讀完了所有的數據,就需要清空緩沖區,讓它可以再次被寫入。有兩種方式能清空緩沖區:調用 clear()或 compact()方法。

      clear()方法會清空整個緩沖區。

      compact()方法只會清除已經讀過的數據。

      任何未讀的數據都被移到緩沖區的起始處,新寫入的數據將放到緩沖區未讀數據的后面。

      2、使用 ByteBuffer的例子
      @Test
      public void testConect2() throws IOException {
          RandomAccessFile aFile = new RandomAccessFile("d:\\achang/01.txt","rw");
          FileChannel inChannel = aFile.getChannel();
          //創建buffer,并指定大?。ㄗ止潱?
          ByteBuffer buf = ByteBuffer.allocate (1024);
          int bytesRead = inChannel.read(buf); //讀取buffer
          while (bytesRead != -1) {
              buf.flip(); //讀寫轉換,為讀模式
              while(buf.hasRemaining()){
                  System.out.print((char) buf.get()); // read 1 byte at a time
              }
              buf.clear(); //清空buffer
              //讀操作
              bytesRead = inChannel.read(buf);
          }
          aFile.close();
      }
      3、使用 IntBuffer 的例子
      @Test
      public void testConect3() throws IOException {
          // 分配新的 int 緩沖區,參數為緩沖區容量
          // 新緩沖區的當前位置將為零,其界限(限制位置)將為其容量。
          // 它將具有一個底層實現數組,其數組偏移量將為零。
          IntBuffer buffer = IntBuffer.allocate (8);
          for (int i = 0; i < buffer.capacity(); ++i) {
              int j = 2 * (i + 1);
              // 將給定整數寫入此緩沖區的當前位置,當前位置遞增
              buffer.put(j);
          }
          // 重設此緩沖區,將限制設置為當前位置,然后將當前位置設置為 0
          buffer.flip();
          // 查看在當前位置和限制位置之間是否有元素
          while (buffer.hasRemaining()) {
              // 讀取此緩沖區當前位置的整數,然后當前位置遞增
              int j = buffer.get();
              System.out.print(j + " ");
          }
      }

      1.3 Buffer 的 capacity、position 和 limit

      為了理解 Buffer 的工作原理,需要熟悉它的三個屬性:

      CapacityPositionlimit

      position 和 limit 的含義取決于 Buffer 處在讀模式還是寫模式。不管 Buffer 處在什么模式,capacity 的含義總是一樣的。

      這里有一個關于 capacity,position 和 limit 在讀寫模式中的說明

      Java Buffer緩沖區(NIO)操作簡介

      (1)capacity

      作為一個內存塊,Buffer 有一個固定的大小值,也叫“capacity”.

      你只能往里寫capacity 個 byte、long,char 等類型。

      一旦 Buffer 滿了,需要將其清空(通過讀數據或者清除數據)才能繼續寫數據往里寫數據。

      (2)position

      寫數據到 Buffer 中時,position 表示寫入數據的當前位置,position 的初始值為0。

      當一個 byte、long 等數據寫到 Buffer 后, position 會向下移動到下一個可插入數據的 Buffer 單元。position 最大可為 capacity – 1(因為 position 的初始值為0).

      讀數據到 Buffer 中時,position 表示讀入數據的當前位置,如 position=2 時表示已開始讀入了 3 個 byte,或從第 3 個 byte 開始讀取。

      通過 ByteBuffer.flip()切換到讀模式時 position 會被重置為 0,當 Buffer 從 position 讀入數據后,position 會下移到下一個可讀入的數據 Buffer 單元。

      (3)limit

      寫數據時,limit 表示可對Buffer 最多寫入多少個數據。寫模式下,limit 等于Buffer 的 capacity。讀數據時,limit 表示 Buffer 里有多少可讀數據(not null 的數據),因此能讀到之前寫入的所有數據(limit 被設置成已寫數據的數量,這個值在寫模式下就是position)。(剩余未讀的數據)

      1.4 Buffer 的類型

      Java NIO 有以下 Buffer 類型

      ByteBufferMappedByteBufferCharBufferDoubleBufferFloatBufferIntBufferLongBufferShortBuffer

      這些 Buffer 類型代表了不同的數據類型。

      換句話說,就是可以通過 char,short,int,long,float 或 double 類型來操作緩沖區中的字節。

      1.5 Buffer 分配和寫數據

      1、Buffer 分配

      要想獲得一個 Buffer 對象首先要進行分配。 每一個 Buffer 類都有一個 allocate 方法。

      下面是一個分配 48 字節 capacity 的 ByteBuffer 的例子。

      ByteBuffer buf = ByteBuffer.allocate(48);

      這是分配一個可存儲 1024 個字符的 CharBuffer:

      CharBuffer buf = CharBuffer.allocate(1024);
      2、向 Buffer 中寫數據

      寫數據到 Buffer 有兩種方式:

      (1)從 Channel 寫到 Buffer。

      (2)通過 Buffer 的 put()方法寫到 Buffer 里。

      從 Channel 寫到 Buffer 的例子

      int bytesRead = inChannel.read(buf); //read into buffer.

      通過 put 方法寫 Buffer 的例子:

      buf.put(127);

      put 方法有很多版本,允許你以不同的方式把數據寫入到 Buffer 中。例如, 寫到一個指定的位置,或者把一個字節數組寫入到 Buffer

      3、flip()方法

      flip 方法將 Buffer 從寫模式切換到讀模式。調用 flip()方法會將 position 設回 0,并將 limit 設置成之前 position 的值。

      換句話說,position 現在用于標記讀的位置,limit 表示之前寫進了多少個 byte、char 等 (現在能讀取多少個 byte、char 等)。

      1.6 從 Buffer 中讀取數據

      從 Buffer 中讀取數據有兩種方式:

      (1)從 Buffer 讀取數據到 Channel。

      (2)使用 get()方法從 Buffer 中讀取數據。

      從 Buffer 讀取數據到 Channel 的例子:

      //read from buffer into channel.
      int bytesWritten = inChannel.write(buf);

      使用 get()方法從 Buffer 中讀取數據的例子

      byte aByte = buf.get();

      get 方法有很多版本,允許你以不同的方式從 Buffer 中讀取數據。例如,從指定position 讀取,或者從 Buffer 中讀取數據到字節數組。

      1.7 Buffer 幾個方法

      1、rewind()方法

      Buffer.rewind()將 position 設回 0,所以你可以重讀 Buffer 中的所有數據。limit 保持不變,仍然表示能從 Buffer 中讀取多少個元素(byte、char 等)。

      2、clear()與 compact()方法

      一旦讀完 Buffer 中的數據,需要讓 Buffer 準備好再次被寫入??梢酝ㄟ^ clear()或compact()方法來完成。

      如果調用的是 clear()方法,position 將被設回 0,limit 被設置成 capacity 的值。換句話說,Buffer 被清空了。Buffer中的數據并未清除,只是這些標記告訴我們可以從哪里開始往 Buffer 里寫數據。

      如果 Buffer 中有一些未讀的數據,調用clear()方法,數據將“被遺忘”,意味著不再有任何標記會告訴你哪些數據被讀過,哪些還沒有。
      如果 Buffer 中仍有未讀的數據,且后續還需要這些數據,但是此時想要先先寫些數據,那么使用 compact()方法。

      compact()方法將所有未讀的數據拷貝到 Buffer 起始處。然后將 position 設到最后一個未讀元素正后面。limit 屬性依然像 clear()方法一樣,設置成 capacity?,F在Buffer 準備好寫數據了,但是不會覆蓋未讀的數據。清除已讀過的數據

      3、mark()與 reset()方法

      事務操作

      通過調用 Buffer.mark()方法,可以標記 Buffer 中的一個特定 position。

      之后可以通過調用Buffer.reset()方法``恢復`到這個 position。例如:

      buffer.mark();
      //call buffer.get() a couple of times, e.g. during parsing.
      buffer.reset(); //set position back to mark.

      1.8、緩沖區操作

      1、緩沖區分片

      在 NIO 中,除了可以分配或者包裝一個緩沖區對象外,還可以根據現有的緩沖區對象來創建一個子緩沖區,即在現有緩沖區上切出一片來作為一個新的緩沖區,但現有的緩沖區與創建的子緩沖區在底層數組層面上是數據共享的,也就是說,子緩沖區相當于是現有緩沖區的一個視圖窗口。調用 slice()方法可以創建一個子緩沖區。

      @Test
      public void testConect3() throws IOException {
          ByteBuffer buffer = ByteBuffer.allocate (10);
          // 緩沖區中的數據 0-9
          for (int i = 0; i < buffer.capacity(); ++i) {
              buffer.put((byte) i);
          }
          // 創建子緩沖區
          buffer.position(3);
          buffer.limit(7);
          ByteBuffer slice = buffer.slice();
          // 改變子緩沖區的內容
          for (int i = 0; i < slice.capacity(); ++i) {
              byte b = slice.get(i);
              b *= 10;
              slice.put(i, b);//指定索引值,修改內容
          }
          //重新指定之前的位置
          buffer.position(0);
          buffer.limit(buffer.capacity());
          while (buffer.remaining() > 0) {
              System. out .println(buffer.get());
          }
      }

      Java Buffer緩沖區(NIO)操作簡介

      2、只讀緩沖區

      只讀緩沖區非常簡單,可以讀取它們,但是不能向它們寫入數據。

      可以通過調用緩沖區的 asReadOnlyBuffer()方法,將任何常規緩沖區轉 換為只讀緩沖區,這個方法返回一個與原緩沖區完全相同的緩沖區,并與原緩沖區共享數據,只不過它是只讀的。

      如果原緩沖區的內容發生了變化,只讀緩沖區的內容也隨之發生變化:

      @Test
      public void testConect4() throws IOException {
          ByteBuffer buffer = ByteBuffer. allocate (10);
          // 緩沖區中的數據 0-9
          for (int i = 0; i < buffer.capacity(); ++i) {
              buffer.put((byte) i);
          }
          // 創建只讀緩沖區
          ByteBuffer readonly = buffer.asReadOnlyBuffer();
          // 改變原緩沖區的內容
          for (int i = 0; i < buffer.capacity(); ++i) {
              byte b = buffer.get(i);
              b *= 10;
              buffer.put(i, b);
          }
          readonly.position(0);
          readonly.limit(buffer.capacity());
          // 讀取只讀緩沖區的內容也隨之改變
          while (readonly.remaining() > 0) {
              System. out .println(readonly.get());
          }
      }

      如果嘗試修改只讀緩沖區的內容,則會報 ReadOnlyBufferException 異常。

      只讀緩沖區對于保護數據很有用。在將緩沖區傳遞給某個 對象的方法時,無法知道這個方法是否會修改緩沖區中的數據。創建一個只讀的緩沖區可以保證該緩沖區不會被修改。

      只可以把常規緩沖區轉換為只讀緩沖區,而不能將只讀的緩沖區轉換為可寫的緩沖區。

      3、直接緩沖區

      直接緩沖區是為加快 I/O 速度,使用一種特殊方式為其分配內存的緩沖區,JDK 文檔中的描述為:給定一個直接字節緩沖區,Java 虛擬機將盡最大努力直接對它執行本機I/O 操作。

      也就是說,它會在每一次調用底層操作系統的本機 I/O 操作之前(或之后),嘗試避免將緩沖區的內容拷貝到一個中間緩沖區中 或者從一個中間緩沖區中拷貝數據。要分配直接緩沖區,需要調用 allocateDirect()方法,而不是 allocate()方法,使用方式與普通緩沖區并無區別。

      拷貝文件示例:

      @Test
      public void testConect5() throws IOException {
          //讀取
          String infile = "d:\\achang\\01.txt";
          FileInputStream fin = new FileInputStream(infile);
          FileChannel fcin = fin.getChannel();
          //輸出
          String outfile = "d:\\achang\\02.txt";
          FileOutputStream fout = new FileOutputStream(outfile);
          FileChannel fcout = fout.getChannel();
          // 使用 allocateDirect,而不是 allocate
          ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
          while (true) {
              buffer.clear();
              int r = fcin.read(buffer);
              if (r == -1) {
                  break;
              }
              buffer.flip();//轉為寫模式
              fcout.write(buffer);
          }
      }
      4、內存映射文件 I/O

      內存映射文件 I/O 是一種讀和寫文件數據的方法,它可以比常規的基于流或者基于通道的 I/O 快的多。

      內存映射文件 I/O 是通過使文件中的數據出現為 內存數組的內容來完成的,這其初聽起來似乎不過就是將整個文件讀到內存中,但是事實上并不是這樣。一般來說,只有文件中實際讀取或者寫入的部分才會映射到內存中。

      示例代碼:MappedByteBuffer

      static private final int start = 0;
      static private final int limit = 1024;
      static public void main(String args[]) throws Exception {
          RandomAccessFile raf = new RandomAccessFile("d:\\achang\\01.txt","rw");
          FileChannel fc = raf.getChannel();
          MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE,start,limit);
          mbb.put(0,(byte) 97);
          mbb.put(1023, (byte) 122);
          raf.close();
      }

      感謝各位的閱讀,以上就是“Java Buffer緩沖區(NIO)操作簡介”的內容了,經過本文的學習后,相信大家對Java Buffer緩沖區(NIO)操作簡介這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

      向AI問一下細節
      推薦閱讀:
      1. Java NIO
      2. java-IO操作簡介

      免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

      AI

      亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女