1. 程式人生 > >2.Buffer 緩沖區

2.Buffer 緩沖區

string 磁盤 執行 重新 mar 復制 div 緩沖區 自管理

/*緩沖區(Buffer)*/

Buffer 就像一個數組,可以保存多個相同類型的數據。根據數據類型不同(boolean 除外),有以下Buffer常用子類:

/*ByteBuffer*/(常用) 、CharBuffer 、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer、DoubleBuffer

上述Buffer 類,他們都采用相似的方式進行管理數據,只是各自管理的數據類型不同而已。都是通過如下方法獲取一個Buffer對象:

  static XxxBuffer allocate(int capacity): 創建一個容量為 capacity 的 XxxBuffer對象



/*緩存區的基本屬性*/

Buffer中的重要概念:

  1.容量(capacity):表示Buffer 最大數據容量,緩沖區容量不能為負,並且創建後不能修改 (創建Buffer對象時 初始化)


  2.限制(limit):第一個不應該讀取或寫入的數據的索引,(即位於limit後的數據不可讀寫)緩沖區的限制 不能為負,並且不能大於其容量


  3.位置(position):下一個要讀取或寫入的數據的索引。緩沖區的位置不能為負,並且不能大於其限制值

  

  4.標記(mark)與重置(reset):標記也是一個索引,通過Buffer中的 mark() 方法指定Buffer中一個特定的position,之後可以通過調用reset()方法恢復到這個 position


標記、位置、限制、容量遵循以下不變式:/*0 <= mark <= position <= limit <= capacity*/


Buffer的常用方法

  Bufffer clear() 清空緩沖區(索引重置為初始狀態)並返回對緩沖區的引用(但是緩沖區的數據依然存在,但是出於 “被遺忘” 狀態)

  Buffer flip() 將緩沖區的界限設置為當前位置,並將當前位置重置為0 (即準備開始操作緩沖區裏面的數據)

緩沖區的數據操作

  Buffer 所有子類提供了 兩個用於數據操作的方法: get() 與 put() 方法


/*直接與非直接緩沖區*/

  非直接緩沖區:通過allocate() 方法 分配緩沖區,將緩沖區建立在 JVM內存中

  直接緩沖區: 通過 allocateDirect() 方法 分配直接緩沖區,將緩沖區建立在物理內存中,可以提高效率

字節緩沖區要麽是直接的,要麽是非直接的。如果是直接字節緩沖區,則Java 虛擬機 會盡最大努力直接在此緩沖區上執行本機 I/O 操作

即直接緩沖區: 通過過一個 ‘物理內存映射文件’ ,將本來要放在JVM內存中的緩沖區 直接放到 物理內存中

非直接緩沖區: 將緩沖區 先放到JVM 的內存中,然後通過 copy ,將內容復制到 內核地址空間(物理內存) ,寫入磁盤


直接緩沖區少了一個 copy 的過程,自然速度會更快,但是也有缺點:1.直接在物理內存上開辟和銷毀空間的代價很大,2.基本上失去了對緩沖區數據的控制,無法控制其銷毀

所以:僅在直接緩沖區能在程序性能方面帶來明顯好處時分配他們

  1 /*
  2  * 一、緩沖區(Buffer):在Java NIO中負責數據的存取。緩沖區就是數組。用於存儲不同數據類型的數據
  3  *
  4  * 根據數據類型不同 (boolean 除外),提供了相應類型的緩沖區
  5  * ByteBuffer(常用) 、CharBuffer、ShortBuffer等
  6  *
  7  * 上述緩沖區 的 管理方式幾乎一致,通過 allocate() 獲取緩沖區
  8  * 
  9  * 二、緩沖區存取數據的兩個核心方法:
 10  * put():存入 數據到緩沖區
 11  * get():獲取緩沖區的數據
 12  * 
 13  * 三、緩沖區的四個核心屬性
 14  * 1.capacity : 容量,表示Buffer 最大數據容量,緩沖區容量不能為負,並且創建後不能修改  (創建Buffer對象時 初始化)
 15  * 
 16  * 2.限制(limit):第一個不應該讀取或寫入的數據的索引,(即位於limit後的數據不可讀寫)
 17                              緩沖區的限制 不能為負,並且不能大於其容量
 18    3.位置(position):下一個要讀取或寫入的數據的索引。緩沖區的位置不能為負,並且不能大於其限制值                         
 19     
 20    4.標記(mark)與重置(reset):標記也是一個索引,通過Buffer中的 mark() 方法指定Buffer中一個特定的position,
 21         之後可以通過調用reset()方法恢復到這個 position                             
 22  * 
 23  *  0 <= mark <= position <= limit <= capacity
 24  *  
 25  *  四、直接緩沖區 和 非直接緩沖區
 26  *  非直接緩沖區:通過allocate() 方法 分配緩沖區,將采取建立在 JVM內存中
 27  *  直接緩沖區:通過 allocateDirect() 方法 分配直接緩沖區,將緩沖區建立在物理內存中,可以提高效率
 28  * 
 29  * */
 30 
 31 public class TestBuffer {
 32     
 33     @Test
 34     public void test3() {
 35         ByteBuffer buffer1 = ByteBuffer.allocateDirect(1024);
 36         System.out.println(buffer1.isDirect());
 37         ByteBuffer buffer2 = ByteBuffer.allocate(1024);
 38         System.out.println(buffer2.isDirect());
 39     }
 40     
 41     @Test
 42     public void test2() {
 43         String str = "abcd";
 44         ByteBuffer buffer = ByteBuffer.allocate(1024);
 45         
 46         buffer.put(str.getBytes());
 47         
 48         buffer.flip();
 49         
 50         byte[] bytes = new byte[buffer.limit()];
 51         buffer.get(bytes,0,2);
 52         
 53         //position = 2
 54         System.out.println(new String(bytes));
 55         System.out.println(buffer.position());
 56         
 57         //標記當前 position
 58         buffer.mark();
 59         
 60         //position = 4
 61         buffer.get(bytes,2,2);
 62         System.out.println(new String(bytes));
 63         System.out.println(buffer.position());
 64         
 65         //將 position reset 到 標記的位置  position = 2
 66         buffer.reset();
 67         System.out.println(buffer.position());
 68     }
 69     
 70     @Test
 71     public void test1() {
 72         //1.分配一個指定大小的緩沖區
 73         ByteBuffer buffer = ByteBuffer.allocate(1024);
 74         System.out.println("-------------allocate()-------------");
 75         System.out.println(buffer.position());
 76         System.out.println(buffer.limit());
 77         System.out.println(buffer.capacity());
 78         
 79         //2.利用 put() 存入數據到緩沖區
 80         String str = "abcedf";
 81         buffer.put(str.getBytes());
 82         System.out.println("-------------put()-------------");
 83         System.out.println(buffer.position());     //此時 位置 索引會變成6,即下一個要讀取或寫入的數據的索引 是 6 (byte[6])
 84         System.out.println(buffer.limit());
 85         System.out.println(buffer.capacity());
 86         
 87         //3.使用 get() 讀取數據之前,需要調用 flip() 方法,切換到 讀取數據模式 (將position置為0,limit置為原先position)
 88         //不然按照現在的所以 是無法讀取到任何數據的
 89         buffer.flip();
 90         System.out.println("-------------flip()-------------");
 91         System.out.println(buffer.position());     
 92         System.out.println(buffer.limit());
 93         System.out.println(buffer.capacity());
 94                 
 95         //4.利用 get() 讀取緩沖區中的數據
 96         //讀取 需要創建一個容器去裝
 97         byte[] bytes = new byte[buffer.limit()];
 98         //將讀取到的數據 放到 這個 byte數組中
 99         buffer.get(bytes);
100         
101         System.out.println("-------------get()-------------");
102         System.out.println(buffer.position());     
103         System.out.println(buffer.limit());
104         System.out.println(buffer.capacity());
105         System.out.println(new String(bytes,0,bytes.length));
106         
107         //5.rewind() 可重復讀  將位置設成 0 ,取消設置的 remark,現在就可以重新讀取了
108         buffer.rewind();
109         System.out.println("-------------rewind()-------------");
110         System.out.println(buffer.position());     
111         System.out.println(buffer.limit());
112         System.out.println(buffer.capacity());
113         
114         //6.clear()  清空緩存區,緩沖區中的數據依然存在,但是 處於 ‘被遺忘’狀態
115         buffer.clear();
116         System.out.println("-------------clear()-------------");
117         System.out.println(buffer.position());     
118         System.out.println(buffer.limit());
119         System.out.println(buffer.capacity());
120         
121         System.out.println((char)buffer.get());
122     }
123 }

2.Buffer 緩沖區