欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Buffer緩沖區(qū)(NIO)

 更新時間:2021年09月12日 10:47:13   作者:阿昌喜歡吃黃桃  
Java NIO(New IO)是從Java 1.4版本開始引入的一個新的IO API,可以替代標準的Java IO API。本系列教程將有助于你學習和理解Java NIO。

Java NIO(Buffer)

1.1 Buffer 簡介

Java NIO 中的 Buffer 用于和 NIO 通道進行交互。數(shù)據(jù)是從通道讀入緩沖區(qū),從緩沖區(qū)寫入到通道中的。

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-4NvO2WG0-1631371913192)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911220012609.png)]

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

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

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

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

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xmz2qs55-1631371913195)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911220129447.png)]

1.2 Buffer 的基本用法

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

(1)寫入數(shù)據(jù)到 Buffer

(2)調(diào)用 flip()方法

(3)從 Buffer 中讀取數(shù)據(jù)

(4)調(diào)用 clear()方法或者 compact()方法

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

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

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

compact()方法只會清除已經(jīng)讀過的數(shù)據(jù)。

任何未讀的數(shù)據(jù)都被移到緩沖區(qū)的起始處,新寫入的數(shù)據(jù)將放到緩沖區(qū)未讀數(shù)據(jù)的后面。

2、使用 ByteBuffer的例子

@Test
public void testConect2() throws IOException {
    RandomAccessFile aFile = new RandomAccessFile("d:\\achang/01.txt","rw");
    FileChannel inChannel = aFile.getChannel();
    //創(chuàng)建buffer,并指定大小(字節(jié))
    ByteBuffer buf = ByteBuffer.allocate (1024);
    int bytesRead = inChannel.read(buf); //讀取buffer
    while (bytesRead != -1) {
        buf.flip(); //讀寫轉(zhuǎn)換,為讀模式
        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 緩沖區(qū),參數(shù)為緩沖區(qū)容量
    // 新緩沖區(qū)的當前位置將為零,其界限(限制位置)將為其容量。
    // 它將具有一個底層實現(xiàn)數(shù)組,其數(shù)組偏移量將為零。
    IntBuffer buffer = IntBuffer.allocate (8);
    for (int i = 0; i < buffer.capacity(); ++i) {
        int j = 2 * (i + 1);
        // 將給定整數(shù)寫入此緩沖區(qū)的當前位置,當前位置遞增
        buffer.put(j);
    }
    // 重設(shè)此緩沖區(qū),將限制設(shè)置為當前位置,然后將當前位置設(shè)置為 0
    buffer.flip();
    // 查看在當前位置和限制位置之間是否有元素
    while (buffer.hasRemaining()) {
        // 讀取此緩沖區(qū)當前位置的整數(shù),然后當前位置遞增
        int j = buffer.get();
        System.out.print(j + " ");
    }
}

1.3 Buffer 的 capacity、position 和 limit

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

CapacityPositionlimit

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

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

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-A0u57DWf-1631371913198)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911214306000.png)]

(1)capacity

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

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

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

(2)position

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

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

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

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

(3)limit

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

1.4 Buffer 的類型

Java NIO 有以下 Buffer 類型

ByteBufferMappedByteBufferCharBufferDoubleBufferFloatBufferIntBufferLongBufferShortBuffer

這些 Buffer 類型代表了不同的數(shù)據(jù)類型。

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

1.5 Buffer 分配和寫數(shù)據(jù)

1、Buffer 分配

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

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

ByteBuffer buf = ByteBuffer.allocate(48);

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

CharBuffer buf = CharBuffer.allocate(1024);

2、向 Buffer 中寫數(shù)據(jù)

寫數(shù)據(jù)到 Buffer 有兩種方式:

(1)從 Channel 寫到 Buffer。

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

從 Channel 寫到 Buffer 的例子

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

通過 put 方法寫 Buffer 的例子:

buf.put(127);

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

3、flip()方法

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

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

1.6 從 Buffer 中讀取數(shù)據(jù)

從 Buffer 中讀取數(shù)據(jù)有兩種方式:

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

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

從 Buffer 讀取數(shù)據(jù)到 Channel 的例子:

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

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

byte aByte = buf.get();

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

1.7 Buffer 幾個方法

1、rewind()方法

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

2、clear()與 compact()方法

一旦讀完 Buffer 中的數(shù)據(jù),需要讓 Buffer 準備好再次被寫入。可以通過 clear()或compact()方法來完成。

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

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

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

3、mark()與 reset()方法

事務(wù)操作

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

之后可以通過調(diào)用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、緩沖區(qū)操作

1、緩沖區(qū)分片

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

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

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-2SY6Ci9G-1631371913206)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911223844959.png)]

2、只讀緩沖區(qū)

只讀緩沖區(qū)非常簡單,可以讀取它們,但是不能向它們寫入數(shù)據(jù)。

可以通過調(diào)用緩沖區(qū)的 asReadOnlyBuffer()方法,將任何常規(guī)緩沖區(qū)轉(zhuǎn) 換為只讀緩沖區(qū),這個方法返回一個與原緩沖區(qū)完全相同的緩沖區(qū),并與原緩沖區(qū)共享數(shù)據(jù),只不過它是只讀的。

如果原緩沖區(qū)的內(nèi)容發(fā)生了變化,只讀緩沖區(qū)的內(nèi)容也隨之發(fā)生變化:

@Test
public void testConect4() throws IOException {
    ByteBuffer buffer = ByteBuffer. allocate (10);
    // 緩沖區(qū)中的數(shù)據(jù) 0-9
    for (int i = 0; i < buffer.capacity(); ++i) {
        buffer.put((byte) i);
    }
    // 創(chuàng)建只讀緩沖區(qū)
    ByteBuffer readonly = buffer.asReadOnlyBuffer();
    // 改變原緩沖區(qū)的內(nèi)容
    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());
    // 讀取只讀緩沖區(qū)的內(nèi)容也隨之改變
    while (readonly.remaining() > 0) {
        System. out .println(readonly.get());
    }
}

如果嘗試修改只讀緩沖區(qū)的內(nèi)容,則會報 ReadOnlyBufferException 異常。

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

只可以把常規(guī)緩沖區(qū)轉(zhuǎn)換為只讀緩沖區(qū),而不能將只讀的緩沖區(qū)轉(zhuǎn)換為可寫的緩沖區(qū)。

3、直接緩沖區(qū)

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

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

拷貝文件示例:

@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();//轉(zhuǎn)為寫模式
        fcout.write(buffer);
    }
}

4、內(nèi)存映射文件 I/O

內(nèi)存映射文件 I/O 是一種讀和寫文件數(shù)據(jù)的方法,它可以比常規(guī)的基于流或者基于通道的 I/O 快的多。

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

示例代碼: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();
}

總結(jié)·

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • SpringBoot整合Log4j2及配置步驟

    SpringBoot整合Log4j2及配置步驟

    這篇文章主要介紹了SpringBoot整合Log4j2以及配置詳解,刪除spring-boot-starter-parent默認使用spring-boot-starter-logging依賴,本文結(jié)合實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-01-01
  • 詳談Spring對IOC的理解(推薦篇)

    詳談Spring對IOC的理解(推薦篇)

    下面小編就為大家?guī)硪黄斦凷pring對IOC的理解(推薦篇)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-10-10
  • Java的string類為什么是不可變的

    Java的string類為什么是不可變的

    這篇文章主要介紹了Java的string類為什么是不可變的,總結(jié)了三個答案,需要的朋友可以參考下
    2014-04-04
  • JAVA 運算符歸納總結(jié)

    JAVA 運算符歸納總結(jié)

    這篇文章主要對Java語法基礎(chǔ)之運算符進行了詳細的歸納總結(jié),需要的朋友可以參考
    2017-04-04
  • mybatis單筆批量保存實體數(shù)據(jù)的方法

    mybatis單筆批量保存實體數(shù)據(jù)的方法

    這篇文章主要介紹了mybatis單筆批量保存實體數(shù)據(jù)的相關(guān)知識,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2018-01-01
  • nodejs與JAVA應(yīng)對高并發(fā)的對比方式

    nodejs與JAVA應(yīng)對高并發(fā)的對比方式

    這篇文章主要介紹了nodejs與JAVA應(yīng)對高并發(fā)的對比方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • 如何使用Logback日志保存到相對路徑

    如何使用Logback日志保存到相對路徑

    在使用Logback中需要保存輸出日志,但是卻在保存的時候路徑出現(xiàn)問題,下面通過案例代碼講解如何使用Logback日志保存到相對路徑,感興趣的朋友一起看看吧
    2025-05-05
  • springboot使用redis對單個對象進行自動緩存更新刪除的實現(xiàn)

    springboot使用redis對單個對象進行自動緩存更新刪除的實現(xiàn)

    本文主要介紹了springboot使用redis對單個對象進行自動緩存更新刪除的實現(xiàn),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java發(fā)送郵件遇到的常見需求匯總

    Java發(fā)送郵件遇到的常見需求匯總

    這篇文章主要介紹了Java發(fā)送郵件遇到的常見需求匯總的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • 利用Java代碼寫一個并行調(diào)用模板

    利用Java代碼寫一個并行調(diào)用模板

    這篇文章主要介紹了利用Java代碼寫一個并行調(diào)用模板,文章基于Java的相關(guān)內(nèi)容展開寫一個并行調(diào)用模板的詳細介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05

最新評論