广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java Buffer缓冲区(NIO)
  • 688
分享到

Java Buffer缓冲区(NIO)

2024-04-02 19:04:59 688人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录Java NIO(Buffer)1.1 Buffer 简介1.2 Buffer 的基本用法1、使用 Buffer 读写数据,一般遵循以下四个步骤:2、使用 ByteBuffer的

Java NIO(Buffer)

1.1 Buffer 简介

Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4NvO2WG0-1631371913192)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911220012609.png)]

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成 NIO Buffer 对象,并提供了一组方法,用来方便的访问该块内存。

缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在 NIO 库中,所有数据都是用缓冲区处理的。

在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流 I/O系统中,所有数据都是直接写入或者直接将数据读取到 Stream 对象中。

在 NIO 中,所有的缓冲区类型都继承于抽象类 Buffer,最常用的就是 ByteBuffer,对于 Java 中的基本类型,基本都有一个具体 Buffer 类型与之相对应,它们之间的继承关系如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xmz2qs55-1631371913195)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911220129447.png)]

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 在读写模式中的说明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A0u57DWf-1631371913198)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911214306000.png)]

(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。现在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());
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2SY6Ci9G-1631371913206)(C:/Users/PePe/AppData/Roaming/Typora/typora-user-images/image-20210911223844959.png)]

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();
}

总结·

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Java Buffer缓冲区(NIO)

本文链接: https://www.lsjlt.com/news/135414.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java Buffer缓冲区(NIO)
    目录Java NIO(Buffer)1.1 Buffer 简介1.2 Buffer 的基本用法1、使用 Buffer 读写数据,一般遵循以下四个步骤:2、使用 ByteBuffer的...
    99+
    2022-11-12
  • Java NIO 中Buffer 缓冲区解析
    目录一、Buffer 简介二、Buffer 的基本方法1、使用 Buffer 读写数据2、使用 Buffer 的例子三、Buffer 的 capactity、posittion 和l...
    99+
    2022-11-13
  • Java NIO中Buffer缓冲区有什么用
    这篇文章主要介绍Java NIO中Buffer缓冲区有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Buffer 简介Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是通道...
    99+
    2023-06-29
  • Node.js Buffer(缓冲区)
    Node.js Buffer(缓冲区)JavaScript 语言自身只有字符串数据类型,没有二进制数据类型。但在处理像TCP流或文件流时,必须使用到二进制数据。因此在 Node.js中,定义了一个 Buffer 类,该类用来创建一个专门存放...
    99+
    2023-06-03
  • 浅析Java NIO 直接缓冲区和非直接缓冲区
    定义 以上是书《深入理解java虚拟机》对直接内存的描述。直接缓冲区用的就是直接内存。 java nio字节缓冲区要么是直接的,要么是非直接的。如果为直接字节缓冲区,则j...
    99+
    2022-11-12
  • Java NIO直接缓冲区和非直接缓冲区是什么
    这篇文章主要讲解了“Java NIO直接缓冲区和非直接缓冲区是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java NIO直接缓冲区和非直接缓冲区是什么”吧!定义j...
    99+
    2023-06-21
  • node.js缓冲区buffer的详细介绍
    这篇文章主要介绍“node.js缓冲区buffer的详细介绍”,在日常操作中,相信很多人在node.js缓冲区buffer的详细介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2022-10-19
  • 浅谈C++ 缓冲区(buffer)的使用
    缓冲区 缓冲区 (buffer) 是内存空间的一部分. 在内存中会为每一个数据流开辟一个内存缓冲区. 缓冲区是用来存放流中的数据, 缓冲区中的数据就是流. 在 C++ 中, 输入输出...
    99+
    2022-11-12
  • MySQL中读页缓冲区buffer pool详解
    目录Buffer poolbuffer pool组成free链表缓存页的哈希处理flush链表的管理LRU链表刷新脏页多个buffer pool实例动态调整buffer pool大小...
    99+
    2022-11-13
  • java中NIO通道和缓冲区是如何工作的
    这篇文章将为大家详细讲解有关java中NIO通道和缓冲区是如何工作的,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。通道 和 缓冲区 是 NIO 中的核心对象,几乎在每一个 I/O 操作中都要使用它们。通道...
    99+
    2023-06-17
  • 如何通过JAVA NIO直接缓冲区拷贝文件
    这篇文章主要为大家展示了“如何通过JAVA NIO直接缓冲区拷贝文件”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何通过JAVA NIO直接缓冲区拷贝文件”这篇文章吧。通过JAVA NIO 直...
    99+
    2023-06-17
  • 如何通过JAVA NIO非直接缓冲区拷贝文件
    小编给大家分享一下如何通过JAVA NIO非直接缓冲区拷贝文件,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!通过JAVA NIO 非直接缓冲区拷贝文件 ...
    99+
    2023-06-17
  • 一文带你了解Golang中的缓冲区Buffer
    目录1. Buffer 是什么2. 创建缓冲区2.1 使用 NewBuffer 函数创建2.2 使用 bytes.Buffer 结构体创建3. 写入数据4. 读取数据5. 截取缓冲区...
    99+
    2023-05-18
    Go 缓冲区Buffer Go 缓冲区 Go Buffer
  • Node.js缓冲区(Buffer)模块的方法及实例分析
    二进制流是大量的二进制数据的集合。由于通常情况下二进制流的大小挺大的,因此二进制流一般不会一起运送,而会在运输前切分成小块然后逐一发送。 当数据处理单元暂时不再接收其他数据流时,剩余...
    99+
    2022-11-12
  • MySQL中读页缓冲区buffer pool的知识点有哪些
    这篇“MySQL中读页缓冲区buffer pool的知识点有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“My...
    99+
    2023-06-30
  • 详解MySQL中的缓冲池(buffer pool)
    Mysql 中数据是要落盘的,这点大家都知道。读写磁盘速度是很慢的,尤其和内存比起来更是没的说。但是,我们平时在执行 SQL 时,无论写操作还是读操作都能很快得到结果,并没有预想中的那么慢。 可能你会说我有索引啊,有...
    99+
    2022-05-16
    MySQL 缓冲池 MySQL buffer pool
  • Java NIO Buffer实现原理详解
    目录1、Buffer的继承体系2、Buffer的操作API使用案例3、Buffer的基本原理4、allocate方法初始化一个指定容量大小的缓冲区5、slice方法缓冲区分片6、只读...
    99+
    2022-11-12
  • Java中的Netty缓冲区的用法
    这篇文章主要介绍“Java中的Netty缓冲区的用法”,在日常操作中,相信很多人在Java中的Netty缓冲区的用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的Netty缓冲区的用法”的疑惑有所...
    99+
    2023-06-16
  • Java NIO Buffer实现原理是什么
    本篇内容介绍了“Java NIO Buffer实现原理是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1、Buffe...
    99+
    2023-06-21
  • 【Linux】文件缓冲区
    目录 一、缓冲区图解二、自定义实现文件操作函数三、强制刷新内核缓冲区(fsync) 提到文件缓冲区这个概念我们好像并不陌生,但是我们对于这个概念好像又是模糊的存在脑海中,之间我们在介绍...
    99+
    2023-09-06
    linux 网络
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作