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

news/2024/6/29 15:24:37

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

	/***
     * channel用例
     * 基于channel的文件复制
     */
    @Test
    public 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://lihuaxi.xjx100.cn/news/1396472.html

相关文章

VR全景旅游,智慧文旅发展新趋势!

引言: VR全景旅游正在带领我们踏上一场全新的旅行体验。这种沉浸式的旅行方式,让我们可以足不出户,却又身临其境地感受世界各地的美景。 一.VR全景旅游是什么? VR全景旅游是一种借助虚拟现实技术,让用户…

Java编程优化代码心得 分层设计和设计模式引入 常用技巧的好坏

需求 经常写代码的同学,一个类通篇几千行,一个方法动不动就几百行,那我优化一下,重构一个方法,这个类的行数反而更多。 然后,各种百度谷歌搜索怎么优化代码。 搜索出的结果,通篇都是优化技巧。…

使用 DolphinDB TopN 函数探索高效的Alpha因子

DolphinDB 已经有非常多的窗口计算函数,例如 m 系列的滑动窗口计算,cum 系列累计窗口计算,tm 系列的的时间窗口滑动计算。但是所有这类函数都是对窗口内的所有记录进行指标计算,难免包含很多噪音。 DolphinDB 的金融领域用户反馈…

【构造】CF1758 C

Problem - 1758C - Codeforces 题意&#xff1a; 思路&#xff1a; 思路&#xff1a; #include <bits/stdc.h>#define int long longusing namespace std;const int mxn2e510; const int mxe2e510;int N,x; int ans[mxn];void solve(){cin>>N>>x;if(N%x!0)…

【程序】【必须】PID位置环控制,代码+调参

​ 前面两篇博文已经实现了电机测速和PID速度环控制&#xff0c;在这篇博文中&#xff0c;我们主要说明位置环的代码怎么写以及PID参数怎么调。 1. 位置环代码实现 ​ 写完速度环后位置环就很简单了。 ​ 在串级PID中&#xff0c;内环的控制量一般是外环控制量的微分。在我们…

英语语法 基础知识(5大基本句型,9大句子成分,10大词性)

目录 一、英语五大基本句型 1.主语 谓语(不及物动词) (状语) : 1 介绍 2 示例 2.主语 谓语(及物动词) 宾语 : 1 介绍 2 示例 3.主语 谓语 间接宾语 直接宾语 : 1 介绍 2 示例 4.主语 谓语 宾语 宾语补足语 : 1 介绍 2 示例 5.主语 系动词 表语 : 1 介绍 2 …

【多模态】22、UniDetector | 检测开放世界中的一切!(CVPR2023)

文章目录 一、背景二、方法2.1 UniDetector 框架结构2.2 Heterogeneous Label Space Training2.3 open-world inference 三、效果3.1 数据集3.2 Object Detection in the Open World3.3 Object Detection in the Closed World3.4 Object Detection in the Wild3.5 Comparison w…

文件头大全

各文件头尾知识点&#xff1a; 1.图片文件 JPEG (jpg/jpe/jpeg) 文件头&#xff1a;FFD8FF 文件尾&#xff1a;FF D9 PNG (png) 文件头&#xff1a;89504E47 文件尾&#xff1a;AE 42 60 82 GIF (gif) 文件头&a…