首页 > 代码库 > 通道和缓冲区
通道和缓冲区
- 通道
通道可以理解成一种连接,根据连接对象的不同,可以分为下面这些类型
文件连接:FileChannel,用于文件的读写
UDP连接:DatagramChannel,用于UDP数据的读写
Socket客户端:SocketChannel,用于TCP数据的读写
Socket服务端:ServerSocketChanel,用于监听TCP连接,每个请求都会生成一个SocketChannel
通道的作用相当于基本IO中的流,但有如下几点区别:
1、通道可以读也可以写,而流只能读或者写
2、通道可以异步读写,而流在读或写的时候,都是阻塞的
3、通道总是基于缓冲区Buffer来读写的,而流的读写是基于虚拟机内存的
demo01:使用通道来进行文件的读取
1 /** 2 * 使用通道读文件数据 3 */ 4 public void readFile() { 5 Path path = Paths.get("/Users/sherry/WorkPath/Git/LinkTest/zln-learning/testDir/content.html"); 6 Charset charset = Charset.forName("UTF-8"); 7 CharsetDecoder decoder = charset.newDecoder();//解码器 8 9 try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) { 10 ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileChannel.size()); 11 CharBuffer charBuffer = CharBuffer.allocate((int) fileChannel.size()); 12 logger.debug("缓冲区大小:"+(int) fileChannel.size());//371 13 if ((fileChannel.read(byteBuffer)) != -1) {//因为缓存容量的缘故,其实只需要读取一次 对于大文件,需要循环 14 logger.debug("ByteBuffer limit:"+byteBuffer.limit());//371 15 byteBuffer.flip();//limit到当前位置 pos到0 16 decoder.decode(byteBuffer, charBuffer, true);//将读取到的字节按照指定方式进行解码,写入到字符缓冲区中 17 logger.debug("CharBuffer limit:"+charBuffer.limit());//371 18 charBuffer.flip(); 19 System.out.print(charBuffer); 20 21 byteBuffer.clear(); 22 charBuffer.clear(); 23 } 24 } catch (IOException e) { 25 logger.error(e.getMessage(), e); 26 } 27 }
用到了如下知识
1、Path表示路径
2、使用CharserDecoder进行解码
3、ByteBuffer到CharBuffer之间使用解码器进行转换
4、使用TWR实现资源的安全关闭
5、缓冲区的flip与clear操作
demo02:使用通道实现文件的写入
1 /** 2 * 打开并写数据 3 * 4 * @throws IOException 5 */ 6 public void openAndWrite() throws IOException { 7 Charset charset = Charset.forName("UTF-8"); 8 CharsetEncoder encoder = charset.newEncoder(); 9 //已有的File流,一般也提供了 getChannel 方法,用于获取 FileChannel 实例 10 try (FileChannel fileChannel = FileChannel.open(Paths.get("/Users/sherry/WorkPath/Git/LinkTest/zln-learning/testDir/fileChannel.txt") 11 , StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE)) { 12 ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 4); 13 CharBuffer charBuffer = CharBuffer.allocate(1024 * 4); 14 for (int i = 0; i < 100; i++) { 15 String writeStr = "张柳宁 - " + UUID.randomUUID().toString() + System.lineSeparator();//待写入的数据 16 charBuffer.put(writeStr); 17 charBuffer.flip(); 18 encoder.encode(charBuffer, byteBuffer, true); 19 byteBuffer.flip(); 20 fileChannel.write(byteBuffer); 21 byteBuffer.clear(); 22 charBuffer.clear(); 23 } 24 25 } 26 }
- 缓冲区
缓冲区根据缓存的内容不同,可以分为如下几类
CharBuffer
DoubleBuffer
LongBuffer
Buffer本质是就是一块内存区,可以用来读写数据,这块内存被NIO包装起来,对外提供了一系列便于开发的接口
先来说说Buffer的共性
1、capacity,所有的缓冲区都有一个初始大小,它代表了这块缓冲区的容量,不可改变
2、limit,读写操作允许的最大位置。刚开始创建的时候,limit等于capacity
3、position,当前读写位置。初始化时为0.一旦写数据,写一个就往后移动一个单元,最大值为capacity-1
Buffer提供的很多方式都是在对以上三个属性进行操作
举例:
读缓冲区前:调用flip,limit设为当前的position,position设为0.这样在读取的时候才能将有效数据全部读取出来
读缓冲区后:如果全部读完了,调用clear,对Buffer重新初始化,compact 方法会将已经读取到的数据清除出缓冲区,未读取的数据通通往前移
重复读取:rewind,将position设为0,limit保持不变
其他操作
mark,记录当前position
reset,恢复到mark时候的position
其他方法详见API
关于limit,Buffer在读和写的时候含义有所区别,见下图
通道和缓冲区