一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java Buffer緩沖區(NIO)

Java Buffer緩沖區(NIO)

2021-12-28 13:36阿昌喜歡吃黃桃 Java教程

Java NIO(New IO)是從Java 1.4版本開始引入的一個新的IO API,可以替代標準的Java IO API。本系列教程將有助于你學習和理解Java NIO。

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的例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@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 的例子

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@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 的例子。

?
1
ByteBuffer buf = ByteBuffer.allocate(48);

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

?
1
CharBuffer buf = CharBuffer.allocate(1024);

2、向 Buffer 中寫數據

寫數據到 Buffer 有兩種方式:

(1)從 Channel 寫到 Buffer。

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

從 Channel 寫到 Buffer 的例子

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

通過 put 方法寫 Buffer 的例子:

?
1
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 的例子:

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

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

?
1
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。現在Buffer 準備好寫數據了,但是不會覆蓋未讀的數據。清除已讀過的數據

3、mark()與 reset()方法

事務操作

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

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

?
1
2
3
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()方法可以創建一個子緩沖區。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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()方法,將任何常規緩沖區轉 換為只讀緩沖區,這個方法返回一個與原緩沖區完全相同的緩沖區,并與原緩沖區共享數據,只不過它是只讀的。

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@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()方法,使用方式與普通緩沖區并無區別。

拷貝文件示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@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

?
1
2
3
4
5
6
7
8
9
10
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();
}

總結·

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關注服務器之家的更多內容!

原文鏈接:https://blog.csdn.net/qq_43284469/article/details/120244580

 

延伸 · 閱讀

精彩推薦
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    這篇文章主要介紹了Java使用SAX解析xml的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下...

    大行者10067412021-08-30
  • Java教程Java8中Stream使用的一個注意事項

    Java8中Stream使用的一個注意事項

    最近在工作中發現了對于集合操作轉換的神器,java8新特性 stream,但在使用中遇到了一個非常重要的注意點,所以這篇文章主要給大家介紹了關于Java8中S...

    阿杜7482021-02-04
  • Java教程Java實現搶紅包功能

    Java實現搶紅包功能

    這篇文章主要為大家詳細介紹了Java實現搶紅包功能,采用多線程模擬多人同時搶紅包,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙...

    littleschemer13532021-05-16
  • Java教程xml與Java對象的轉換詳解

    xml與Java對象的轉換詳解

    這篇文章主要介紹了xml與Java對象的轉換詳解的相關資料,需要的朋友可以參考下...

    Java教程網2942020-09-17
  • Java教程Java BufferWriter寫文件寫不進去或缺失數據的解決

    Java BufferWriter寫文件寫不進去或缺失數據的解決

    這篇文章主要介紹了Java BufferWriter寫文件寫不進去或缺失數據的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望...

    spcoder14552021-10-18
  • Java教程升級IDEA后Lombok不能使用的解決方法

    升級IDEA后Lombok不能使用的解決方法

    最近看到提示IDEA提示升級,尋思已經有好久沒有升過級了。升級完畢重啟之后,突然發現好多錯誤,本文就來介紹一下如何解決,感興趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程小米推送Java代碼

    小米推送Java代碼

    今天小編就為大家分享一篇關于小米推送Java代碼,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧...

    富貴穩中求8032021-07-12
  • Java教程20個非常實用的Java程序代碼片段

    20個非常實用的Java程序代碼片段

    這篇文章主要為大家分享了20個非常實用的Java程序片段,對java開發項目有所幫助,感興趣的小伙伴們可以參考一下 ...

    lijiao5352020-04-06
主站蜘蛛池模板: 日韩亚洲人成网站在线播放 | 日韩欧美在线一区二区三区 | 日韩特级片 | 91国产在线视频 | 91传媒制片厂制作传媒破解版 | 美女黄板视频 | 非洲黑女人性xxxx | 日韩成人影视 | 成年美女黄网站色视频大全免费 | 亚洲免费在线观看 | 欧美18-19sex性处| 久久受www免费人成_看片中文 | 精品国产成人高清在线 | 寡妇一级毛片 | 日本大尺度激情做爰叫床 | 五月天色小说 | 亚洲色影 | 村妇超级乱淫伦小说全集 | 成人在线第一页 | 精品久久久久久亚洲精品 | 亚洲女性色尼古综合网 | 男人操女人动图 | 国产午夜久久精品 | 69罗莉视频在线观看 | av91在线| 国产精品亚洲w码日韩中文 国产精品香蕉在线观看不卡 | 国产黄频在线观看高清免费 | 四虎影视在线影院在线观看 | 本站只有精品 | 污黄漫| 国产亚洲精品日韩香蕉网 | 美国一级大黄大色毛片 | 万域之王在线观看 | 免费视频观看 | 日韩欧美在线观看综合网另类 | 亚洲haose在线观看 | 国产精品久久久久a影院 | 肉车各种play文r | 久久日韩精品无码一区 | 日本肉体xxxx69xxxx | 9久re热视频这里只有精品 |