文章目录
一、缓冲区 (xxBuffer)
【1】简介
简介:一个用于指定基本数据类型的容器。由 java.nio 包定义的,所有缓冲区都是 Buffer 抽象类的子类。
作用:主要用于与 NIO 通道进行交互。
【2】缓冲区的基本属性
| 属性 | 定义 |
|---|---|
| 容量 (capacity) | 表示 Buffer 最大数据容量,缓冲区容量不能为负,并且创 建后不能更改。 |
| 限制 (limit) | 第一个不应该读取或写入的数据的索引,即位于 limit 后的数据 不可读写。(0 <= limit <= capacity)。 |
| 位置 (position) | 下一个要读取或写入的数据的索引。缓冲区的位置不能为 负,并且不能大于其限制 |
| 标记 (mark) 重置 (reset) | 标记是一个索引,通过 Buffer 中的 mark() 方法 指定 Buffer 中一个特定的 position,之后可以通过调用 reset() 方法恢复到这 个 position. |
他们遵守以下不变式: 0 <= mark <= position <= limit <= capacity
【3】缓冲区方法演示
| 方 法 | 描述 |
|---|---|
| Buffer clear() | 清空缓冲区并返回对缓冲区的引用 |
| Buffer flip() | 将缓冲区的界限设置为当前位置,并将当前位置充值为 0 |
| int capacity() | 返回 Buffer 的 capacity 大小 |
| boolean hasRemaining() | 判断缓冲区中是否还有元素 |
| int limit() | 返回 Buffer 的界限 (limit) 的位置 |
| Buffer limit(int n) | 将设置缓冲区界限为 n, 并返回一个具有新 limit 的缓冲区对象 |
| Buffer mark() | 对缓冲区设置标记 |
| int position() | 返回缓冲区的当前位置 position |
| Buffer position(int n) | 将设置缓冲区的当前位置为 n , 并返回修改后的 Buffer 对象 |
| int remaining() | 返回 position 和 limit 之间的元素个数 |
| Buffer reset() | 将位置 position 转到以前设置的 mark 所在的位置 |
| Buffer rewind() | 将位置设为为 0, 取消设置的 mark |
| put(byte[] src) | 将 src 中的字节写入缓冲区的当前位置 |
| put(int index, byte b) | 将指定字节写入缓冲区的索引位置(不会移动 position) |
| get(int index) | 读取指定索引位置的字节(不会移动 position) |
allocate()
@Test public void test1(){ String str = "abcde"; //1. 分配一个指定大小的缓冲区 ---> 0、10、10 ByteBuffer buf = ByteBuffer.allocate(10); System.out.println(buf.position() + buf.limit() + buf.capacity()); 
put()
//2. 利用 put() 存入数据到缓冲区中 ---> 5、10、10 buf.put(str.getBytes()); System.out.println(buf.position() + buf.limit() + buf.capacity()); 
flip()
//3. 切换读取数据模式 ---> 0、5、10 buf.flip(); System.out.println(buf.position() + buf.limit() + buf.capacity()); 
limit()、mark()、reset()
//4. 利用 get() 读取缓冲区中的数据 ---> 5、5、10 byte[] dst = new byte[buf.limit()]; buf.get(dst); System.out.println(new String(dst, 0, dst.length)); System.out.println(buf.position()+buf.limit()+buf.capacity()); buf.mark(); buf.get(dst, 2, 2); System.out.println(new String(dst, 2, 2)); System.out.println(buf.position()); //2 buf.reset(); System.out.println(buf.position()); //4 rewind()
//5. rewind() (回倒 == 恢复初始位置)可重复读 ---> 0、5、10 buf.rewind(); System.out.println(buf.position() + buf.limit() + buf.capacity()); clear()
//6. clear() : 清空缓冲区. buf.clear(); //---> 0、10、10 (回到最初状态) System.out.println(buf.position() + buf.limit() + buf.capacity()); System.out.println((char)buf.get()); ע:clear() 后,缓冲区中的数据依然存在,只是处于“被遗忘”状态
【4】直接与非直接缓冲区


| 直接缓冲区 | 非直接缓冲区 |
|---|---|
| byteBuffer.allocateDirect() | byteBuffer.allocat() |
| 一般仅在直接缓冲区能在程序性能方面带来明显好处时使用它 | |
| 鉴别:isDirect() |
二、通道 (Channel)

最初:如果有大量的 IO 操作 (IO接口的调用),那么CPU的IO操作部分的占用率会很高。于是
DMA的出现:DMA 会先向 CPU 申请处理IO的权限,这样可以减负CPU (其中会建立DMA总线,DMA总线过多会出现总线冲突问题) ―> Channel的出现。
Channel (完全独立的处理器):减负CPU.
Channel 的作用:用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。
【1】主要实现类
| (本地 IO / 网络 IO).getChannel()获取 | 描述 |
|---|---|
| 用于读取、写入、映射和操作文件的通道。 | |
| 通过 UDP 读写网络中的数据通道。 | |
| 通过 TCP 读写网络中的数据。 | |
| 可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChannel。 |
【2】获取通道
① 对支持通道的(流)对象调用 getChannel() 方法。支持通道的类如下:
- FileInputStream、FileOutputStream、RandomAccessFile
- DatagramSocket、Socket、ServerSocket
② 使用 Files 类的静态方法 newByteChannel() 获
取字节通道。
③ 通过相应Channel的静态方法 open() 方法返回指定通道。
【3】通道的数据传输
一、利用通道完成文件的复制(非直接缓冲区)
@Test public void test1(){ //10874-10953 FileInputStream fis = null; FileOutputStream fos = null; //1. 定义通道引用 FileChannel inChannel = null, outChannel = null; try{ fis = new FileInputStream("d:/1.mkv"); fos = new FileOutputStream("d:/2.mkv"); inChannel = fis.getChannel(); outChannel = fos.getChannel(); //2. 分配指定大小的缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //3. 将通道中的数据存入缓冲区中 while(inChannel.read(buf) != -1){ //buffer的初始状态是写入模式. buf.flip(); //切换读取数据的模式 outChannel.write(buf); //4. 将缓冲区中的数据写入通道中 buf.clear(); //清空缓冲区 } }catch(){} finally {} } 二、使用直接缓冲区完成文件的复制 (内存映射文件)
来源:51CTO
作者:Shonan_
链接:https://blog.csdn.net/qq_43539599/article/details/100833041