1. Buffer 类是 java.nio 的构造基础。一个 Buffer 对象是固定数量的、数据的容器,其作用是一个存储器或者分段运输区。在这里,数据可被存储并在之后用于检索。缓冲区可以被写满或释放。对于每个非布尔类型的、原始数据类型都有一个缓冲区类,即 Buffer 的子类有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和 ShortBuffer,是没有 BooleanBuffer 之说的。尽管缓冲区作用于它们存储的原始数据类型,但缓冲区十分倾向于处理字节。
  2. Buffer及其子类都不是线程安全的,若多线程操作该缓冲区,则应通过同步来控制对该缓冲区的访问。
  3. 每个Buffer都有以下四个属性:
    (1) capacity:容量,缓冲区能够容纳的数据元素的最大数量。这一容量在缓冲区创建时被设定,且永远不能被改变
    (2) limit:上界,缓冲区的第一个不能被读或写的元素。缓冲区创建时,limit 的值等于 capacity 的值。假设 capacity = 1024,我们在程序中设置了 limit = 512,说明Buffer 的容量为 1024,但是从 512 之后既不能读也不能写,因此可以理解成,Buffer 的实际可用大小为 512
    (3) position:位置,下一个要被读或写的元素的索引。位置会自动由相应的 get() 和 put() 函数更新。 这里需要注意的是positon的位置是从0开始,比如,已经写入buffer 3个元素那那么position就是指向第4个位置,即position设置为3(数组从0开始计)
    (4) mark:标记,一个备忘位置。保存某个时刻的position指针的值,通过调用mark()实现,当mark被置为负值时,表示废弃标记。标记在设定前是未定义的(undefined)。使用场景是,假设缓冲区中有 10 个元素,position 目前的位置为 2(也就是如果get的话是第三个元素),现在只想发送 6 - 10 之间的缓冲数据,此时我们可以 buffer.mark(buffer.position());即把当前的 position 记入 mark 中,然后 buffer.postion(6);此时发送给 channel 的数据就是 6 - 10 的数据。发送完后,我们可以调用 buffer.reset() 使得 position = mark,因此这里的 mark 只是用于临时记录一下位置用的
    (5) position和limit之间的距离指定了可读/写的字节数
    (6) mark,position,limit,capacity大小关系:
	-1 <= mark <= position <= limit <= capacity
			0<= position <= limit <= capacity
  1. 常用的方法一:
    (1) clear(),把position设为0,把limit设为capacity,取消标记,一般在把数据写入Buffer前调用,Buffer中的数据并未清除,只是这些标记告诉我们可以从哪里开始往Buffer里写数据。如果Buffer中有一些未读的数据,调用clear()方法以后,数据将“被遗忘”,意味着不再有任何标记会告诉你哪些数据被读过,哪些还没有。源码如下:
    public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
    }

    (2) compact(),如果Buffer中仍有未读的数据,且后续还需要这些数据,但是此时想要先写些数据,那么使用compact()方法。compact()方法将所有未读的数据拷贝到Buffer起始处。然后将position设到最后一个未读元素正后面。limit属性依然像clear()方法一样,设置成capacity。现在Buffer准备好写数据了,但是不会覆盖未读的数据。
    (3) flip(),把limit设为当前position,把position设为0,取消标记,一般在从Buffer中读取数据前调用。源码如下:
    public final Buffer flip() {
    limit = position;
    position = 0;
    mark = -1;
    return this;
    }

    (4) rewind(),把position设为0,limit不变,一般在把数据重写入Buffer前调用。源码如下:
    public final Buffer rewind() {
    position = 0;
    mark = -1;
    return this;
    }

    (5) hasRemaining(),当缓冲区至少还有一个元素时,返回true;
    (6) remaining(),position和limit之间字节个数;
    (7) reset(),将position的值还原成上次调用mark()方法后的position的值。源码如下:
    public final Buffer reset() {
    int m = mark;
    if (m < 0)
    throw new InvalidMarkException();
    position = m;
    return this;
    }

  2. 常用方法二:
    (1) allocate(),分配一个具有指定大小的底层数组,并将它包装到一个缓冲区对象中,用静态方法 allocate() 来分配缓冲区;
    (2) wrap(),将一个已有的byte数组包装出一个新的bytebuffer对象;
    (3) slice(),根据现有的缓冲区创建一个子缓冲区。也就是它创建一个新的缓冲区,新缓冲区与原来的缓冲区的一部分共享数据,子缓冲区和缓冲区 共享同一个底层数据数组,分片操作是根据当前position以及limit的值来确定的;
    (4) order(),返回ByteBuffer的字节序;

  3. 视图缓冲区,可以用ByteBuffer对象创建其他类型的缓冲区,新缓冲区共享原始ByteBuffer的全部或者部分内存,这样的缓冲区被叫做视图缓冲区,就是通过源缓冲区创建其他的基础数据类型的缓冲区,新缓冲区和源缓冲区共享数据,但各自维护自己的属性(capacity、limit、position、mark)。

  4. 使用Buffer读/写数据一般遵循以下四个步骤:
    (1) 写入数据到Buffer;
    (2) 调用flip()方法;
    (3) 从Buffer中读取数据;
    (4) 调用clear()方法或者compact()方法;

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

Buffer 类是 java.nio 的构造基础。一个 Buffer 对象是固定数量的、数据的容器,其作用是一个存储器或者分段运输区。在这里,数据可被存储并在之后用于检索。缓冲区可以被写满或释放。对于每个非布尔类型的、原始数据类型都有一个缓冲区类,即 Buffer 的子类有:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和 ShortBuffer,是没有 BooleanBuffer 之说的。...... 在Java nio中,主要有三大组件:Buffer,Channel和Selector。这三者之间的关系可以按照如下方式进行理解: Buffer提供了一个字节缓冲区,其可以不断的从Channel中读取接收到的数据。Buffer的优点主要在于其提供了一系列的Api,能够让用户更方便的对数据进行读取和写入; Channel简单来说就是一个信道,也就是客户端与服务器的一个连接,而且每个客户端都会对应一个Channel对象; Selector是Java nio能够支持高并发数据处理一个关键,其核心理 Buffer是nio包的一个抽象类,作为java nio的三大组件(Buffer、Channel,Selector)之一,在java nio网络编程中尤为重要。 Buffer提供了一个字节缓冲区,配合Channel使用,可以从Channel中读取或写入数据。 以ByteBuffer为例,其包括5个主要的属性:hb、position、limit、capacity、mark。 hb:ByteBuffer类有一个byte数组变量hb,此数组里面存放的就是实际的字节数据。 capaci Buffer类(缓冲区) 概述:Buffer是一个抽象类,它是对某种基本类型的数组进行了封装。 作用: 在NIO中,就是通过 Buffer 来读写数据的。所有的数据都是用Buffer来处理的,它是NIO读写数据的中转池, 通常使用字节数组。 Buffer主要有如下几种: ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer 创建ByteBufferByteBufferJava nio程序经常会用到的类,也是重要类 ,我们通过源码分析该类的实现原理。 一.ByteBuffer类的继承结构 public abstract class ByteBufferextends Bufferimplements Comparable&lt;ByteBuffer&gt; ByteBuffer的核心特性来自Buffer 二. ByteB...
缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区: 使用缓冲区有这么两个好处: 1、减少实际的物理读写次数 2、缓冲区在创建时就被分配内存,这块内存区域一直被重用,可以减少动态分配和回收内存的次数 举个简单的例子,比如A地有1w块砖要搬到B地 由于没有工具(缓冲区),我们一次只能搬一本,那么就要搬1w次(
java的内存分为堆内内存和堆外内存,在了解堆外内存之前,先看看堆内内存是啥,堆内内存是受jvm管控的,也就是说,堆内内存由jvm负责创建和回收;创建和回收都是自动进行的,不需要人为干预; 什么是堆外内存 堆外内存又叫直接内存,是和操作系统内存直接挂钩的,堆外内存不受jvm的管制,所以可以认为堆外内存是jvm以外的内存空间,虽然不受jvm管控,但是堆外内存还是在java进程里面的,而不是由系统内核直接管理;所以它还是在java进程里面的;(终究逃不出java的手掌心); 堆外内存和堆内内存他俩是
在NIO中,数据的读写操作始终是与缓冲区相关联的.读取时信道(SocketChannel)将数据读入缓冲区,写入时首先要将发送的数据按顺序填入缓冲区.缓冲区是定长的,基本上它只是一个列表,它的所有元素都是基本数据类型.ByteBuffer是最常用的缓冲区,它提供了读写其他数据类型的方法,且信道的读写方法只接收ByteBuffer.因此ByteBuffer的用法是有必要牢固掌握的. 1.创建Byt
ByteBuffer的原理和使用详解1.ByteBuffer的2种创建方式2.字符串转成ByteBuffer的3三种方式3.Bytebuffer的读写底层原理 ByteBuffer是字节缓冲区,主要用户读取和缓存字节数据,多用于网络编程,Netty框架的重要知识点 1.ByteBuffer的2种创建方式 1.ByteBuffer buf = ByteBuffer.allocate(int size); 方式1的buf缓冲区存储在堆内存中,内存开销在JVM中,受GC影响,会多拷贝一次,因为java程序收到的数
import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileReadWriteExample { public static void main(String[] args) { try { // 打开一个 RandomAccessFile 对象,以读写模式打开文件 RandomAccessFile file = new RandomAccessFile("example.txt", "rw"); FileChannel channel = file.getChannel(); // 创建一个 ByteBuffer,设置容量为 1024 字节 ByteBuffer buffer = ByteBuffer.allocate(1024); // 从文件中读取数据到 ByteBuffer int bytesRead = channel.read(buffer); while (bytesRead != -1) { buffer.flip(); // 切换为读模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); // 读取字节并输出 buffer.clear(); // 清空 ByteBuffer bytesRead = channel.read(buffer); // 继续从文件中读取数据 // 向文件中写入数据 String data = "Hello, World!"; buffer.clear(); buffer.put(data.getBytes()); buffer.flip(); // 切换为写模式 channel.write(buffer); // 关闭文件流 file.close(); } catch (Exception e) { e.printStackTrace(); 在上面的示例中,首先创建了一个`RandomAccessFile`对象,并通过`getChannel()`方法获取了`FileChannel`对象。然后,创建了一个`ByteBuffer`对象,并设置了容量为1024字节。接下来,使用`channel.read(buffer)`方法从文件中读取数据到`ByteBuffer`,并通过`buffer.flip()`方法切换为读模式。然后,使用`buffer.get()`方法逐个读取字节并输出。当`buffer`中没有剩余字节时,使用`buffer.clear()`方法清空`ByteBuffer`。重复执行以上步骤,直到读取到文件末尾。最后,使用`buffer.put(data.getBytes())`方法将数据写入`ByteBuffer`,并通过`buffer.flip()`方法切换为写模式。最后,使用`channel.write(buffer)`方法将数据写入文件中。最后,记得关闭文件流。 SpringBoot - MyBatis-Plus - UpdateWrapper、LambdaUpdateWrapper和LambdaUpdateChainWrapper的用法(四) 15839