亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

Java NIO(Buffer)

1.1 Buffer 簡介

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

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(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í)際上是一個(gè)容器對象,更直接的說,其實(shí)就是一個(gè)數(shù)組,在 NIO 庫中,所有數(shù)據(jù)都是用緩沖區(qū)處理的。

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

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

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

1.2 Buffer 的基本用法

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

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

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

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

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

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

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

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

compact()方法只會(huì)清除已經(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ū)的當(dāng)前位置將為零,其界限(限制位置)將為其容量。
    // 它將具有一個(gè)底層實(shí)現(xiàn)數(shù)組,其數(shù)組偏移量將為零。
    IntBuffer buffer = IntBuffer.allocate (8);
    for (int i = 0; i < buffer.capacity(); ++i) {
        int j = 2 * (i + 1);
        // 將給定整數(shù)寫入此緩沖區(qū)的當(dāng)前位置,當(dāng)前位置遞增
        buffer.put(j);
    }
    // 重設(shè)此緩沖區(qū),將限制設(shè)置為當(dāng)前位置,然后將當(dāng)前位置設(shè)置為 0
    buffer.flip();
    // 查看在當(dāng)前位置和限制位置之間是否有元素
    while (buffer.hasRemaining()) {
        // 讀取此緩沖區(qū)當(dāng)前位置的整數(shù),然后當(dāng)前位置遞增
        int j = buffer.get();
        System.out.print(j + " ");
    }
}

1.3 Buffer 的 capacity、position 和 limit

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

CapacityPositionlimit

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

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

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

(1)capacity

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

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

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

(2)position

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

當(dāng)一個(gè) byte、long 等數(shù)據(jù)寫到 Buffer 后, position 會(huì)向下移動(dòng)到下一個(gè)可插入數(shù)據(jù)的 Buffer 單元。position 最大可為 capacity – 1(因?yàn)?position 的初始值為0).

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

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

(3)limit

寫數(shù)據(jù)時(shí),limit 表示可對Buffer 最多寫入多少個(gè)數(shù)據(jù)。寫模式下,limit 等于Buffer 的 capacity。讀數(shù)據(jù)時(shí),limit 表示 Buffer 里有多少可讀數(shù)據(jù)(not null 的數(shù)據(jù)),因此能讀到之前寫入的所有數(shù)據(jù)(limit 被設(shè)置成已寫數(shù)據(jù)的數(shù)量,這個(gè)值在寫模式下就是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 分配

要想獲得一個(gè) Buffer 對象首先要進(jìn)行分配。 每一個(gè) Buffer 類都有一個(gè) allocate 方法。

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

ByteBuffer buf = ByteBuffer.allocate(48);

這是分配一個(gè)可存儲(chǔ) 1024 個(gè)字符的 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 中。例如, 寫到一個(gè)指定的位置,或者把一個(gè)字節(jié)數(shù)組寫入到 Buffer

3、flip()方法

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

換句話說,position 現(xiàn)在用于標(biāo)記讀的位置,limit 表示之前寫進(jìn)了多少個(gè) byte、char 等 (現(xiàn)在能讀取多少個(gè) 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 幾個(gè)方法

1、rewind()方法

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

2、clear()與 compact()方法

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

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

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

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

3、mark()與 reset()方法

事務(wù)操作

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

之后可以通過調(diào)用Buffer.reset()方法``恢復(fù)`到這個(gè) 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 中,除了可以分配或者包裝一個(gè)緩沖區(qū)對象外,還可以根據(jù)現(xiàn)有的緩沖區(qū)對象來創(chuàng)建一個(gè)子緩沖區(qū),即在現(xiàn)有緩沖區(qū)上切出一片來作為一個(gè)新的緩沖區(qū),但現(xiàn)有的緩沖區(qū)與創(chuàng)建的子緩沖區(qū)在底層數(shù)組層面上是數(shù)據(jù)共享的,也就是說,子緩沖區(qū)相當(dāng)于是現(xiàn)有緩沖區(qū)的一個(gè)視圖窗口。調(diào)用 slice()方法可以創(chuàng)建一個(gè)子緩沖區(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)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(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ū),這個(gè)方法返回一個(gè)與原緩沖區(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)容,則會(huì)報(bào) ReadOnlyBufferException 異常。

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

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

3、直接緩沖區(qū)

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

也就是說,它會(huì)在每一次調(diào)用底層操作系統(tǒng)的本機(jī) I/O 操作之前(或之后),嘗試避免將緩沖區(qū)的內(nèi)容拷貝到一個(gè)中間緩沖區(qū)中 或者從一個(gè)中間緩沖區(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)容來完成的,這其初聽起來似乎不過就是將整個(gè)文件讀到內(nèi)存中,但是事實(shí)上并不是這樣。一般來說,只有文件中實(shí)際讀取或者寫入的部分才會(huì)映射到內(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默認(rèn)使用spring-boot-starter-logging依賴,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-01-01
  • 詳談Spring對IOC的理解(推薦篇)

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

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

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

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

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

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

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

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

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

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

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

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

    springboot使用redis對單個(gè)對象進(jìn)行自動(dòng)緩存更新刪除的實(shí)現(xiàn)

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

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

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

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

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

最新評論