搞活系列-Java NIO之偏偏不用buffer.flip()会出现什么问题?

news/2025/2/12 8:33:08/

最近看博客又看到了Java NIO相关的博客,其中有讲解NIO和传统IO关于文件复制的文章,看到了如下的代码:

	/**** channel用例* 基于channel的文件复制*/@Testpublic void fileCopyByChannel(){try {FileInputStream fileInputStream = new FileInputStream(fielPathIN);FileOutputStream fileOutputStream = new FileOutputStream(fielPathOUT);FileChannel inputStreamChannel = fileInputStream.getChannel();FileChannel outputStreamChannel = fileOutputStream.getChannel();ByteBuffer buffer = ByteBuffer.allocate(1024);int i = 1;while ((i = inputStreamChannel.read(buffer) )!= -1) {buffer.flip();Charset charset = StandardCharsets.UTF_8;outputStreamChannel.write(buffer);buffer.clear();}fileInputStream.close();fileOutputStream.close();inputStreamChannel.close();outputStreamChannel.close();} catch (Exception e) {e.printStackTrace();}}

逻辑也比较简单,只是将一个文件中的文本内复制到另外一个文件中。

关键知识点

  • FileInputStream 、FileOutputStream 通过.getChannel()获取FileChannel
  • ByteBuffer.allocate(1024)分配堆内存,还有另外一种分配直接内存的方式allocateDirect。两者分配的内存前面的是归JVM管理的,儿后者不归JVM管理
  • buffer.flip()切换为读模式
  • buffer.flip()清空buffer。注意:并不是清空数据,而是重置状态

开始搞活

刚刚看到这段代码,我迫不及待去试了下,很nice!然后,脑子里就出了一个很奇怪的想法:如果在while循环里面没有buffer.flip()会怎样。

while中如果没有buffer.flip()

说搞就搞,注解注释掉,截图为证
在这里插入图片描述
运行一下代码看看效果,结果真的运行完成了,出乎意料了,难道flip可有可无了?然后就去磁盘里面看了代码运行完成的文件
在这里插入图片描述
看到这里,果然有问题,那就是flip方法是必须要有的。那么,为什么生成的代码只有源文件的一部分呢?是哪一部分呢?

flip方法详细解释

flip()方法将缓冲区的limit设置为当前的position,同时将position设置为0,以准备读取缓冲区中的数据。

clear方法详细解释

  • 将position重置为0,以便下一次写入新的数据。
  • 将缓冲区的limit设置为缓冲区的容量,表示缓冲区的可写入或可读取的上限。

显然,每次循环的最后都调用了clear方法,都会将buffer重置,所以每次都能从channel中读取到数据;因为没有调用flip方法,所以除了最后一次循环,之前循环读取完数据之后,postion、limit和capcity都在buffer的最后了,而读取的时候读的内容是从postion开始,一直到limit结束。
因为你最后一次读取如果不是1024的整数倍,假如说是100,那这一次的循环buffer的position是101,limit是1024,capcity是1024,那么将读取上一次从101-1024之间的内容。而除了最后一次循环的之前所有循环都读取不到数据。

说着可能太抽象了,还是画个图说明一下
在这里插入图片描述
所以说,最后一次读取到的是上一次没有覆盖完的内容。

那如果循环里面没有clear方法会怎么样呢?

while中如果没有buffer.clear()

详细看看以上关于clear方法的介绍,应该能知道会出现什么结果。因为clear会重置buffer的状态,如果不重置,那么从channel读取数据写入到buffer中时,只有第一次会是成功写入的,第一次之后position、limit和capcity都将指向最后,而写入时,要从position开始写一直到capcity结束;第一次写入完成之后将一直读取不了channel中的数据,因此也将会程序也将死循环。

总结

  • buffer如果是写入之后要读取,那么读取之前一定要先flip
  • buffer如果是读取之后要写入,那么写入之前一定要先clear

以上就是本篇文章所有内容,如果有写的不对的地方,欢迎大家指正,谢谢阅读!


http://www.ppmy.cn/news/993456.html

相关文章

Linux-MySQL安装

配置: 1.VMware workstation pro 2.MySQL 3.centOS 5.7版本 1.配置yum仓库 #更新密钥 rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022#安装 rpm --Uvh https://repo.mysql.com//mysql57-community-release-el7-7.noarch.rpm 2.安装mysql yum …

day02_springboot综合案例

day02_springboot综合案例 订单操作 查询所有订单 查询所有订单流程 查询订单,要把订单对应的产品也要查出来 Orders实体类 Data public class Orders {private String id;private String orderNum;DateTimeFormat(pattern"yyyy-MM-dd HH:mm")privat…

IRQ和FIQ有什么区别,在CPU里面是怎么做的

IRQ(Interrupt Request)和 FIQ(Fast Interrupt Request)是 ARM 架构中用于处理中断的两种不同类型。 区别如下: 优先级:FIQ 具有更高的优先级,即当 FIQ 发生时,CPU 会在当前指令执行…

【Linux】关于Bad magic number in super-block 当尝试打开/dev/sda1 时找不到有效的文件系统超级块

每个区段与 superblock 的信息都可以使用 dumpe2fs 这个指令来查询的! 不过可惜的是,我们的 CentOS 7 现在是以 xfs 为默认文件系统, 所以目前你的系统应该无法使用 dumpe2fs 去查询任何文件系统的。 因为目前两个版本系统的根目录使用的文…

C程序设计:状态机

1.状态机简介 状态机是一种常用的编程模型,用于描述系统的状态和状态之间的转换规则。无论使用何种操作系统或编程框架,状态机都可以用来帮助设计和实现系统的逻辑。即使在使用 FreeRTOS 的情况下,如果系统的逻辑需要描述为多个状态和状态转换…

螺旋矩阵 II——力扣59

文章目录 题目描述法一 模拟 题目描述 法一 模拟 初始化一个二维向量&#xff0c;名为matrix&#xff0c;它有n行和n列。向量的每个元素都是一个整数&#xff0c;初始化为0。初始化二维向量的语法如下&#xff1a;vector<vector<int>> matrix(n, vector<int>…

goctl template一定制化服务配置生成

官网介绍&#xff1a; 模板&#xff08;Template&#xff09;是数据驱动生成的基础&#xff0c;所有的代码&#xff08;rest api、rpc、model、docker、kube&#xff09;生成都会依赖模板&#xff0c; 默认情况下&#xff0c;模板生成器会选择内存中的模板进行生成&#xff0c…

开发者必看,各类热门免费api推荐

核验类 运营商三要素 API&#xff1a;输入姓名、身份证号码、手机号码&#xff0c;验证此三种信息是否一致&#xff0c;返回验证结果、手机归属地、运营商名称。银行卡三要素&#xff1a;检测输入的姓名、身份证号码、银行卡号是否一致。毫秒级响应、直联保障&#xff0c;支持…