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

最近看博客又看到了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.mzph.cn/news/17659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript 【type】关键字的进阶使用方式

导语: 在前面章节中,我们了解到 TS 中 type 这个关键字,常常被用作于,定义 类型别名,用来简化或复用复杂联合类型的时候使用。同时也了解到 为对象定义约束接口类型 的时候所使用的是 Interfaces。 其实对于前面&#…

iOS 应用上架流程详解

iOS 应用上架流程详解 欢迎来到我的博客,今天我将为大家分享 iOS 应用上架的详细流程。在这个数字化时代,移动应用已经成为了人们生活中不可或缺的一部分,而 iOS 平台的 App Store 则是开发者们发布应用的主要渠道之一。因此,了解…

智安网络|常见的网络安全陷阱:你是否掉入了其中?

在数字化时代,网络安全成为了一个重要的议题。随着我们越来越多地在互联网上进行各种活动,诸如在线银行交易、社交媒体分享和在线购物等,我们的个人信息也更容易受到攻击和滥用。虽然有许多关于网络安全的指导和建议,但仍然有许多…

【ChatGPT】ChatGPT是如何训练得到的?

前言 ChatGPT是一种基于语言模型的聊天机器人,它使用了GPT(Generative Pre-trained Transformer)的深度学习架构来生成与用户的对话。GPT是一种使用Transformer编码器和解码器的预训练模型,它已被广泛用于生成自然语言文本的各种…

【前端知识】React 基础巩固(四十)——Navigate导航

React 基础巩固(四十)——Navigate导航 一、Navigate的基本使用 新建Login页面,在Login中引入Navigate,实现点击登陆按钮跳转至/home路径下: import React, { PureComponent } from "react"; import { Navigate } from "reac…

HTML5 API 多端通信桥 MessageChannel 技术

这个特别有意思,可以将其理解为通信桥的概念,桥有两个端(port1,port2)只要将port1,port2指定到任意两个进程,无论是iframe-iframe,iframe-worker,parent-child-iframe&am…

【数据结构】图文并茂,通过逻辑图带你轻松拿捏链表,实现各种接口功能

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,米娜桑们,这里是君兮_,我们接着之前讲过的顺序表来继续介绍初阶数据结构的内容,今天给大家带来的是有关链表的基本知识和各种接口功能的实现 好了,废话不多说&#x…

LeetCode 周赛上分之旅 # 36 KMP 字符串匹配殊途同归

⭐️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问。 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越抽象,它能覆盖的问题域就越广,理解难度…

day50-Insect Catch Game(捉虫游戏)

50 天学习 50 个项目 - HTMLCSS and JavaScript day50-Insect Catch Game&#xff08;捉虫游戏&#xff09; 效果 index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport"…

codeblocks编译lvgl报错

codeblocks编译lvgl报错 1.报错内容2.解决方案3.lvgl本身代码报错 1.报错内容 error: unknown type name _In_opt_ ...2.解决方案 官网下载&#xff1a; 这里的Compiler’s installation directory 选择自带的 3.lvgl本身代码报错 undefined reference to _lv_utils_bse…

面试总结-Redis篇章(九)——Redis主从复制、主从数据同步原理

Redis其他面试问题 主从复制单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离主节点主要进行客户端的写操作&#xff0c;从节点进行客户端的读操作&#xff0c;因为Redis一直都是读多写少&…

UE5.1.1 创建C++项目失败

因一直使用Unity开发环境&#xff0c;安装Unreal后&#xff0c;并未详细配置过其开发环境&#xff0c;默认创建蓝图工程无异常&#xff0c;但创建UE C项目时总共遇到两个错误&#xff1a; 错误一 Running /Epic/UE/UE_5.1/Engine/Build/BatchFiles/Build.bat -projectfiles -…

<C++>二、类和对象-构造函数

1.类的6个默认成员函数 如果一个类中什么成员都没有&#xff0c;简称为空类。 空类中真的什么都没有吗&#xff1f;并不是&#xff0c;任何类在什么都不写时&#xff0c;编译器会自动生成以下6个默认成员函数。 默认成员函数&#xff1a;用户没有显式实现&#xff0c;编译器会生…

【Linux多线程】死锁问题介绍

死锁 &#x1f96d;什么是死锁&#x1f965;死锁产生的条件&#x1f95d;如何避免死锁&#x1f345; 避免死锁算法 &#x1f96d;什么是死锁 死锁是多线程或多进程编程中的一种常见问题&#xff0c;指的是两个或多个线程&#xff08;或进程&#xff09;相互等待对方持有的资源&…

搜索二叉树_SearchBinaryTree

目录 搜索二叉树的原理 搜索二叉树的搜索时间复杂度 二叉搜索树实现_key 模型 节点 构造函数 查找 中序遍历 插入 循环 递归 删除 循环 1.删除叶子节点 2.删除有一个孩子的节点 3.左右孩子都不为空 递归 析构函数 拷贝构造 operator key_value 模型 节点 …

Mysql触发器

1.触发器 触发器是与表有关的数据库对象&#xff0c;指在 insert / update / delete 之前或之后&#xff0c;触发并执行触发器中定义的SL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性&#xff0c;日志记录&#xff0c;数据校验等操作。 使用别名 OLD 和 …

mysql安装教程保姆级

MySQL免安装本地运行 1.下载MySQL2.创建install.bat3.init.sql 初始创建4.环境变量配置5.运行 install.bat 管理员权限运行6.连接成功遇到的问题 1.下载MySQL ①地址&#xff1a;https://downloads.mysql.com/archives/community/ ②解压 2.创建install.bat 放在mysql>b…

算法综合篇专题一:双指针问题

"就算没有看清那株灿烂的花蕊&#xff0c;也应该放声歌颂赞美鲜红的玫瑰" 1、移动零 (1) 题目解析 (2) 算法原理 class Solution { public:void moveZeroes(vector<int>& nums) {for(int cur0,dest-1;cur<nums.size();cur){if(nums[cu…

java设计模式-建造者(Builder)设计模式

介绍 Java的建造者&#xff08;Builder&#xff09;设计模式可以将产品的内部表现和产品的构建过程分离开来&#xff0c;这样使用同一个构建过程来构建不同内部表现的产品。 建造者设计模式涉及如下角色&#xff1a; 产品&#xff08;Product&#xff09;角色&#xff1a;被…

前端工程化最佳实践:项目结构、代码规范和文档管理

文章目录 前端工程化最佳实践项目结构设计与组织文档管理和注释规范国际化和本地化实践 前端工程化的未来发展趋势前端工程化领域的最新技术和工具WebAssembly 和前端性能优化可持续性和可访问性的趋势 总结前端工程化的关键知识点前端工程化对项目和团队的价值 前端工程化最佳…