Java NIO 中的 Buffer 缓冲区详解(上)

简介: Java NIO 中的 Buffer 缓冲区详解

Buffer 简介


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


image.png


缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装 NIO Buffer 对象,并且提供了一组方法,用来方便的访问这块内存。缓冲区世纪上一个容器对象,更直接的说,其实就是一个数组,在 NIO 库中,所有数据都是用缓冲区处理的。 在读取数据时,它直接读到缓冲区中;在写数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流 I/O 系统中,所有数据都是直接写入或者直接将数据读取到 Stream 对象中。


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


image.png


Buffer 的基本方法


1、使用 Buffer 读写数据,一般遵循以下四个步骤:


(1)写数据到 Buffer


(2)调用flip() 方法


(3)从 Buffer 中读取数据


(4)调用 clear() 方法或者 compact() 方法


当向 buffer 写数据时,buffer 会记录下写了多少数据。一旦要读数据,需要通过 flip() 方法将 buffer 从写模式切换到读模式。在读模式下,可以读取到之前写入到 buffer 的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用 clear() 或者 compact() 方法。clear() 方法会清空整个缓冲区。compact() 方法只会清除已经度过的数据。任何未读取的数据都被移动到了缓冲区的起始处,新写的数据将放到缓冲区未读数据的后面。


2、使用 Buffer 的例子


@Test
public void buffer01() throws IOException {
    // FileChannel
    String pathName = "/Users/zhengsh/sourcecode.io/zhengsh-vvip/nio/src/main/resources/01.txt";
    RandomAccessFile accessFile =
        new RandomAccessFile(pathName, "rw");
    FileChannel channel = accessFile.getChannel();
    // 创建 buffer , 大小
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    // 读
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        // read 模式
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.println((char) buffer.get());
        }
        buffer.clear();
        channel.read(buffer);
    }
    accessFile.close();
}
@Test
public void buffer02() {
    // 创建 buffer
    IntBuffer buffer = IntBuffer.allocate(8);
    for (int i = 0; i < buffer.capacity(); i++) {
        int j = 2 * (i + 1);
        buffer.put(j);
    }
    // 重置缓冲区
    buffer.flip();
    while (buffer.hasRemaining()) {
        int value = buffer.get();
        System.out.println(value + "  ");
    }
}


Buffer 的 capactity、posittion 和limit


为了理解 Buffer 的工作原理,需要熟悉它的三个属性:


  • capacity


  • ponstition


  • limit


position 和 limit 的含义取决于 Buffer 处在读模式还是写模式。不管 buffer 处于什么模式,capactity 的含义总是一样的。


这里有一个关于 capacity, postition 和 limit 在读模式中的说明:


image.png


(1) capactiy


作为一个内存块,Buffer 有一个固定的大小值,也叫做 “capactiy” . 你只能往里面写 capacity 个 byte


long、 char等类型。一旦 buffer 满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。


(2) postition


1)写数据到 Bufer 中时,position 表示写入数据的当前位置,position 的初始值为 0 。当一个 byte,long,等数据写入到 buffer 后,position 会向下移动到下一个可插入的元素的 buffer 但愿。position 最大可为 capacity -1 (因为 position 的初始值为 0)


2)读数据到 Buffer 中时,position 表示读数据的当前位置,如 position = 2 时表示已经开始读了 3 个 byte, 或者从第三个 byte 开始读取,通过 ByteBuffer.flip() 切换到读模式 position 会被重置为 0, 当 Buffer 从 position 读入数据后,position 会下移到下一个可读入的数据 Buffer 单元。


(3) limit


1)写数据时, limit 表示可以对 Buffer 最多写入多少个数据。写模式下,limit 等于 Buffer 的 capactiy


2)读数据时, limit 表示 Buffer 里有多少可读数据(not null 的数据),因此能读取到之前写入的所有数据(limit 被设置为已写数据的数量,这个值在写模式下就是 position)


Buffer 的类型


Java NIO 有一下 Buffer 的类型


  • ByteBuffer
  • MappedByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • LongBuffer
  • ShortBuffer


这些 buffer 类型都代表了不同的数据类型。换句话说,就是可以通过 char ,short, int, long , float 或者 double 类型来操作缓冲区的字节。


Buffer 分配和写数据


1、 Buffer 分配


想要获取一个 Buffer 对象首先要进行分配。每一个 Buffer 类都有一个 allocate 方法。

下面是一个分配 48 字节 capactiy 的 ByteBuffer 的例子。


ByteBuffer buf = ByteBuffer.alloacte(48);


这是分配一个可存储 1024 个字符的 CharBuffer:


ByteBuffer buf = ByteBuffer.alloacte(1024);


相关文章
|
4月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
14天前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
1月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
29 2
|
2月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
1月前
|
缓存 Java
java文件读取 while ((len = reader.read(buffer)) != -1){}的理解
本文解释了Java中使用`InputStreamReader`和`read(buffer)`方法循环读取文件内容的机制,强调了如何正确理解读取循环和处理读取到的数据,以及如何处理字符编码和换行符。
39 0
|
3月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
83 2
|
3月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
115 0
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
3月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
72 0
|
4月前
|
安全 Java
【Java】已解决java.nio.channels.OverlappingFileLockException异常
【Java】已解决java.nio.channels.OverlappingFileLockException异常
121 1