标签:throw 步骤 参数 上进 必须 file 参考 none 参与
Buffer,故名思意,缓冲区,实际上是一个容器,是一个连续数组。Channel提供从文件、网络读取数据的渠道,但是读取或写入的数据都必须经由Buffer。具体看下面这张图就理解了:
上面的图描述了从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入Buffer中,然后将Buffer中的内容写入通道。服务端这边接收数据必须通过Channel将数据读入到Buffer中,然后再从Buffer中取出数据来处理。
Buffer本质上就是一块内存区,可以用来写入数据,并在稍后读取出来。这块内存被NIO Buffer包裹起来,对外提供一系列的读写方便开发的接口。
在NIO中,Buffer是一个顶层父类,它是一个抽象类,常用的Buffer的子类有:
如果是对于文件读写,上面几种Buffer都可能会用到。但是对于网络读写来说,用的最多的是ByteBuffer。
字节缓冲区和其他缓冲区类型最明显的不同在于,它们可能成为通道所执行I/O的源头或目标,如果对NIO有了解的朋友们一定知道,通道只接收ByteBuffer作为参数。如我们所知道的,操作系统在内存区域进行I/O操作,这些内存区域,就操作系统方面而言,是相连的字节序列。于是,毫无疑问,只有字节缓冲区有资格参与I/O操作
ByteBuffer bf = ByteBuffer.allocate(10); //创建了一个最大容量为10的字节缓冲区
1 package com.test.a; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.nio.ByteBuffer; 8 import java.nio.channels.FileChannel; 9 10 public class Test { 11 public static void main(String[] args) throws IOException{ 12 FileInputStream fileInputStream=new FileInputStream("C:\\Users\\hermioner\\Desktop\\in.txt"); 13 FileChannel fileChannel=fileInputStream.getChannel(); 14 15 FileOutputStream fileOutputStream=new FileOutputStream("C:\\Users\\hermioner\\Desktop\\out.txt"); 16 FileChannel fileChannel2=fileOutputStream.getChannel(); 17 18 //初始化缓冲区 19 ByteBuffer buffer=ByteBuffer.allocate(20); 20 System.out.println("通道文件的大小:"+fileChannel.size()); 21 System.out.println("缓冲区初始化时当前位置:"+buffer.position()); 22 System.out.println("缓冲区初始化时可写的限制:"+buffer.limit()); 23 System.out.println("------------循环开始---------"); 24 25 //判断通道内数据是否读取完成 26 while(-1 != fileChannel.read(buffer)) 27 { 28 System.out.println("缓冲区写模式下当前位置:"+buffer.position()); 29 System.out.println("缓冲区写模式下的限制:"+buffer.limit()); 30 31 //将缓冲区从写模式切换到读模式 32 buffer.flip(); 33 System.out.println("缓冲区读模式下当前位置:"+buffer.position()); 34 System.out.println("缓冲区读模式下的限制:"+buffer.limit()); 35 36 //判断缓冲区内是否还有数据可读取 37 while(buffer.hasRemaining()) { 38 fileChannel2.write(buffer); 39 } 40 buffer.clear(); 41 } 42 fileChannel.close(); 43 fileChannel2.close(); 44 fileOutputStream.close(); 45 fileInputStream.close(); 46 47 } 48 }
1 通道文件的大小:13 2 缓冲区初始化时当前位置:0 3 缓冲区初始化时可写的限制:20 4 ------------循环开始--------- 5 缓冲区写模式下当前位置:13 6 缓冲区写模式下的限制:20 7 缓冲区读模式下当前位置:0 8 缓冲区读模式下的限制:13
执行结果,out.txt文件中的内容和in.txt文件中的内容一样样,且为:
hello,
world
说明:可以看到,在缓冲区写模式下,limit的大小始终等于capacity;而在读模式下,limit等于模式切换前position的大小
position <= limit <= capacity
再举个例子,观察四个值得变化:
(1)创建一个容量大小为10的字节缓冲区
ByteBuffer bf = ByteBuffer.allocate(10);
此时:mark = -1; position = 0; limit =10 ; capacity = 10;
(2)往缓冲区中put五个字节
bf.put((byte)‘H‘).put((byte)‘e‘).put((byte)‘l‘).put((byte)‘l‘).put((byte)‘0‘);
注意这里一个字符是占用两个字节的,但是英文字符只占用一个字节,所以这样是可以实现存储效果的。
此时:此时:mark = -1; position = 5; limit = 10; capacity = 10;
(3)调用flip方法,切换为读就绪状态
bf.flip();
此时:mark = -1; position = 0; limit = 5; capacity = 10;
(4)读取两个元素
System.out.println("" + (char) bf.get() + (char) bf.get());
此时:mark = -1; position = 2; limit = 5; capacity = 10;
(5)标记此时的position位置
bf.mark();
此时:mark = 2; position = 2; limit = 5; capacity = 10;
(6)读取两个元素后,恢复到之前mark的位置处
System.out.println("" + (char) bf.get() + (char) bf.get()); bf.reset();
执行完第二行代码:mark = 2; position = 2; limit = 5; capacity = 10;
(7)调用compact方法,释放已读取数据的空间,准备重新填充缓存区
bf.compact();
此时:mark = 2; position = 3; limit = 10; capacity = 10;
注意观察数组中元素的变化,实际上进行了数组拷贝,抛弃了已读字节元素,保留了未读字节元素;
3.1 flip
buffer.flip()该方法是用于将缓冲区从写模式切换到读模式,这是一种固定写法
public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
3.2 remaind方法
public final Buffer rewind() { position = 0; mark = -1; return this; }
将position的位置设置为0,表示可以重新读取Buffer中的所有数据,limit保持不变。
3.3 clear方法
public final Buffer clear() { position = 0; limit = capacity; mark = -1; return this; }
3.4 向buffer中写入数据
buffer.put("channel".getBytes());
3.5 读取buffer中的数据
byte b = buffer.get();
把数据写入buffer;
调用flip;
从Buffer中读取数据;
调用buffer.clear()或者buffer.compact()。
当写入数据到buffer中时,buffer会记录已经写入的数据大小。当需要读数据时,通过 flip() 方法把buffer从写模式调整为读模式;在读模式下,可以读取所有已经写入的数据。
当读取完数据后,需要清空buffer,以满足后续写入操作。清空buffer有两种方式:调用 clear() 或 compact() 方法。clear会清空整个buffer,compact则只清空已读取的数据,未被读取的数据会被移动到buffer的开始位置,写入位置则近跟着未读数据之后。
参考文献:
https://www.cnblogs.com/dolphin0520/p/3919162.html
https://www.cnblogs.com/dongguacai/p/5812831.html
https://www.cnblogs.com/chenpi/p/6475510.html
标签:throw 步骤 参数 上进 必须 file 参考 none 参与
原文地址:https://www.cnblogs.com/Hermioner/p/9788081.html