【1.2】缓冲区和通道

匿名 (未验证) 提交于 2019-12-03 00:05:01


一、缓冲区 (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 {} } 

二、使用直接缓冲区完成文件的复制 (内存映射文件)

 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!