目录

Channel

FileChannel

打开 FileChannel

从 FileChannel 读数据

写数据到 FileChannel

关闭 FileChannel

示例

读数据

写数据


Channel

在 NIO 中,Channel 和 Buffer 是相辅相成的,只能从 Channel 读取数据到 Buffer 中,或者从 Buffer 写入数据到 Channle,如下图:


Channel 类似于 OIO 中的流(Stream),但是又有所区别:

  • 流是单向的,但 Channel 是双向的,可读可写。
  • 流是阻塞的,但 Channle 可以异步读写。
  • 流中的数据可以选择性的先读到缓存中,而 Channel 的数据总是要先读到一个 Buffer 中,或从 Buffer 中写入,如上图。

NIO 中通过 Channel 封装了对数据源的操作,通过 Channel 可以操作数据源,但是又不必关注数据源的具体物理结构,这个数据源可以是文件,也可以是socket。
Channel 的接口定义如下:

publicinterface Channel extends Closeable {public boolean isOpen();public void close() throws IOException;
}

Channel 接口仅定义两个方法:

  • isOpen():Channel 是否打开
  • close():关闭 Channel

它的主要实现有:

  • FileChannel:文件通道,用于文件的数据读写。
  • SocketChannel:套接字通道,能通过 TCP 读写网络中的数据。
  • ServerSocketChannel:服务器套接字通道,监听新进来的 TCP 连接,像 web 服务器那样,对每一个新进来的连接都会创建一个 SocketChannel
  • DatagramChannel:数据报通道,能通过 UDP 读写网络中的数据。

基本类图如下:


下面就 FileChannel 做详细介绍。 

FileChannel

FileChannel 主要是用来读写和映射一个系统文件的 Channel,它是一个抽象类,具体由 FileChannelImpl 来实现。
定义如下:

package java.nio.channels;
publicabstractclass FileChannelextends AbstractInterruptibleChannelimplements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel{/*** 初始化一个无参构造器.*/protected FileChannel() { }//打开或创建一个文件,返回一个文件通道来访问文件public static FileChannel open(Path path,Set<? extends OpenOption> options,FileAttribute<?>... attrs)throws IOException{FileSystemProvider provider = path.getFileSystem().provider();return provider.newFileChannel(path, options, attrs);}privatestaticfinal FileAttribute<?>[] NO_ATTRIBUTES = new FileAttribute[0];//打开或创建一个文件,返回一个文件通道来访问文件public static FileChannel open(Path path, OpenOption... options)throws IOException{Set<OpenOption> set = new HashSet<OpenOption>(options.length);Collections.addAll(set, options);return open(path, set, NO_ATTRIBUTES);}//从这个通道读入一个字节序列到给定的缓冲区public abstract int read(ByteBuffer dst) throws IOException;//从这个通道读入指定开始位置和长度的字节序列到给定的缓冲区public abstract long read(ByteBuffer[] dsts, int offset, int length)throws IOException;/*** 从这个通道读入一个字节序列到给定的缓冲区*/public final long read(ByteBuffer[] dsts) throws IOException {return read(dsts, 0, dsts.length);}/*** 从给定的缓冲区写入字节序列到这个通道*/public abstract int write(ByteBuffer src) throws IOException;/*** 从给定缓冲区的子序列向该信道写入字节序列*/public abstract long write(ByteBuffer[] srcs, int offset, int length)throws IOException;/*** 从给定的缓冲区写入字节序列到这个通道*/public final long write(ByteBuffer[] srcs) throws IOException {return write(srcs, 0, srcs.length);}/*** 返回通道读写缓冲区中的开始位置*/public abstract long position() throws IOException;/*** 设置通道读写缓冲区中的开始位置*/public abstract FileChannel position(long newPosition) throws IOException;/*** 返回此通道文件的当前大小*/public abstract long size() throws IOException;/*** 通过指定的参数size来截取通道的大小*/public abstract FileChannel truncate(long size) throws IOException;/*** 强制将通道中的更新文件写入到存储设备(磁盘等)中*/public abstract void force(boolean metaData) throws IOException;/*** 将当前通道中的文件写入到可写字节通道中* position就是开始写的位置,long就是写的长度*/public abstract long transferTo(long position, long count,WritableByteChannel target)throws IOException;/*** 将当前通道中的文件写入可读字节通道中* position就是开始写的位置,long就是写的长度*/public abstract long transferFrom(ReadableByteChannel src,long position, long count)throws IOException;/*** 从通道中读取一系列字节到给定的缓冲区中* 从指定的读取开始位置position处读取*/public abstract int read(ByteBuffer dst, long position) throws IOException;/*** 从给定的缓冲区写入字节序列到这个通道* 从指定的读取开始位置position处开始写*/public abstract int write(ByteBuffer src, long position) throws IOException;// -- Memory-mapped buffers --/*** 一个文件映射模式类型安全枚举*/publicstaticclass MapMode {//只读映射模型publicstaticfinal MapMode READ_ONLY= new MapMode("READ_ONLY");//读写映射模型publicstaticfinal MapMode READ_WRITE= new MapMode("READ_WRITE");/*** 私有模式(复制在写)映射*/publicstaticfinal MapMode PRIVATE= new MapMode("PRIVATE");privatefinal String name;private MapMode(String name) {this.name = name;}}/*** 将该通道文件的一个区域直接映射到内存中*/public abstract MappedByteBuffer map(MapMode mode,long position, long size)throws IOException;/*** 获取当前通道文件的给定区域上的锁* 区域就是从position处开始,size长度 * shared为true代表获取共享锁,false代表获取独占锁*/public abstract FileLock lock(long position, long size, boolean shared)throws IOException;/*** 获取当前通道文件上的独占锁*/public final FileLock lock() throws IOException {return lock(0L, Long.MAX_VALUE, false);}/*** 尝试获取给定的通道文件区域上的锁* 区域就是从position处开始,size长度 * shared为true代表获取共享锁,false代表获取独占锁*/public abstract FileLock tryLock(long position, long size, boolean shared)throws IOException;/*** 尝试获取当前通道文件上的独占锁*/public final FileLock tryLock() throws IOException {return tryLock(0L, Long.MAX_VALUE, false);}
}

打开 FileChannel

在使用 FileChannle 之前必须要先打开它,但是无法直接打开一个 FileChannel,需要通过使用一个 InputStream、OutputStream、RandomAcessFile 来获取一个 FileChannel 实例,如下:

RandomAccessFile accessFile = new RandomAccessFile("/Users/chenssy/Documents/FileChannel.txt","rw");
FileChannel fileChannel = accessFile.getChannel();

调用 getChannel() 即可获取 FileChannel 实例,源码如下:

public final FileChannel getChannel() {synchronized (this) {if (channel == null) {channel = FileChannelImpl.open(fd, path, true, rw, this);}return channel;}
}

getChnnel() 方法很简单,直接调用 FileChannelImpl 的静态方法 open()

public static FileChannel open(Path path,Set<? extends OpenOption> options,FileAttribute<?>... attrs) throws IOException{FileSystemProvider provider = path.getFileSystem().provider();return provider.newFileChannel(path, options, attrs);
}

从 FileChannel 读数据

调用 FileChannel 的 read() 方法即可从 FileChannel 中获取数据,当然不是直接获取,而是需要先写入到 Buffer 中,所以调用 read() 之前,需要分配一个 Buffer,然后调用 read() ,该方法返回 int 表示有多少数据读取到了 Buffer 中了,如果返回 -1 表示已经到文件末尾了。

ByteBuffer buffer = ByteBuffer.allocate(1024);
int readCount = fileChannel.read(buffer);

FileChannel 仅定义了方法,具体实现在 FileChannelImpl,如下:

public int read(ByteBuffer dst) throws IOException {ensureOpen();if (!readable)thrownew NonReadableChannelException();// 加锁synchronized (positionLock) {int n = 0;int ti = -1;try {begin();ti = threads.add();if (!isOpen())return0;do {// 通过IOUtil.read实现n = IOUtil.read(fd, dst, -1, nd);} while ((n == IOStatus.INTERRUPTED) && isOpen());return IOStatus.normalize(n);} finally {threads.remove(ti);end(n > 0);assert IOStatus.check(n);}}
}

如果小假的内容对你有帮助,请点赞评论收藏。创作不易,大家的支持就是我坚持下去的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:
http://www.pswp.cn/pingmian/94236.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/94236.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/94236.shtml

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

相关文章

【力扣】2623. 记忆函数——函数转换

【力扣】2623. 记忆函数——函数转换 文章目录【力扣】2623. 记忆函数——函数转换一、题目二、解决方案1、概述1.1纯函数2、在Web开发中的记忆化用途2.1缓存网站文件&#xff08;1&#xff09;React 组件&#xff08;2&#xff09;缓存 API 调用3、算法中的记忆化4、专业实现的…

数据结构 -- 队列

队列的核心定义队列是受限线性表&#xff0c;仅允许在一端&#xff08;队尾&#xff09;插入元素、另一端&#xff08;队头&#xff09;删除元素&#xff0c;遵循 “先进先出&#xff08;FIFO&#xff0c;First In First Out&#xff09;” 原则。队列的结构与操作端队尾&#…

为什么hive在处理数据时,有的累加是半累加数据

在 Hive 处理数据时&#xff0c;“半累加数据” 指的是部分字段保留历史状态、部分字段随业务变化累加或更新的场景&#xff0c;这种模式广泛存在于需要兼顾 “历史追溯” 和 “增量更新” 的业务中。以下是具体例子&#xff0c;帮助理解其本质&#xff1a;例子 1&#xff1a;用…

【贪心算法】day2

&#x1f4dd;前言说明&#xff1a; 本专栏主要记录本人的贪心算法学习以及LeetCode刷题记录&#xff0c;按专题划分每题主要记录&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代码&#xff1b;&#xff08;2&#xff09;优质解法 优质代码&#xff1b;&#xff…

Spring Boot整合RabbitMQ进阶实战:TTL、死信队列与延迟队列深度解析

Spring Boot整合RabbitMQ进阶实战&#xff1a;TTL、死信队列与延迟队列深度解析 一、TTL机制深度解析&#xff1a;从原理到落地 在RabbitMQ的消息生命周期管理中&#xff0c;TTL&#xff08;Time-To-Live&#xff09; 是核心机制之一——它通过设置消息的"存活时长"&…

最新react,vue 解决无法使用js触发点击,解决方案

const elements document.getElementsByClassName(remove-btn-eIaRy9 select-none semi-dropdown-item);if (elements.length > 0) {const element elements[0];const rect element.getBoundingClientRect();// 模拟鼠标移动到元素上const mouseOverEvent document.crea…

一键部署开源 Coze Studio

文章目录一、简介1、什么是 Coze Studio2、参考地址二、安装部署1、安装docker2、安装git3、下载core4、配置公网可用5、登录成功一、简介 1、什么是 Coze Studio Coze Studio 是一站式 AI Agent 开发工具。提供各类最新大模型和工具、多种开发模式和框架&#xff0c;从开发到…

Python Excel 通用筛选函数

案例目的 第一个函数从指定文件路径读取CSV数据并转换为DataFrame&#xff0c;第二个函数使用灵活的条件筛选DataFrame。 示例数据!&idxMarketCURRPMTERMANT……*1JPUSD10…*1CHINAEUR00…*1USAUSD10…*2JPJPY10…*3USACNY11…*4CHINACNY00…*5JPUSD11…*6JPJPY00…假定数据…

鸿蒙中内存泄漏分析

引言&#xff1a;什么是内存泄漏&#xff1f; 想象一下你的手机是一个酒店&#xff0c;每个应用程序都是酒店的客人。当客人&#xff08;应用程序&#xff09;使用房间&#xff08;内存&#xff09;时&#xff0c;酒店经理&#xff08;系统&#xff09;会分配房间给他们使用。…

将windows 的路径挂载到Ubuntu上进行直接访问

1、下载hane NFS Server安装2、安装后打开3、在电脑上创建个共享文件夹&#xff0c;我这里选择D:\share4、在hane win nfs server 软件上选择Edit\preferences5、选择exports6、选择Edit exports file, 在最后添加D:\share -name:nfs&#xff0c;然后点击Save如果添加root权限使…

开源 python 应用 开发(十一)短语音转文本

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

【C++闯关笔记】封装②:友元与模板

系列文章目录 第零篇&#xff1a;从C到C入门&#xff1a;C有而C语言没有的基础知识总结-CSDN博客 第一篇&#xff1a;【C闯关笔记】封装①&#xff1a;类与对象-CSDN博客 第二篇&#xff1a;【C闯关笔记】封装②&#xff1a;友元与模板-CSDN博客 第三篇&#xff1a;【C闯关笔…

Python 爬虫教程 | 豆瓣 TOP250 数据抓取与分析实战

一、项目背景与数据价值豆瓣TOP250是影视行业的重要榜单&#xff0c;具有以下数据价值&#xff1a;评分与评价人数&#xff1a;衡量电影市场热度&#xff1b;导演与演员信息&#xff1a;分析人才价值与影视趋势&#xff1b;类型 / 地区 / 年份&#xff1a;洞察电影类型与年代变…

第04章 SPSS简介与数据库构建

参考&#xff1a;SPSS实战与统计思维 - 武松编著 - 微信读书 4.1 SPSS简介 发展历史 全称Statistical Product and Service Solutions&#xff0c;由美国斯坦福大学三位研究生于1968年开发。 对比其他软件成立时间&#xff1a;SAS&#xff08;1976年&#xff09;、Stata&…

【ABAP4】数据字典

ABAP数据字典ABAP数据字典概述数据字典的基本对象域数据元素表类型系统创建自定义透明表创建自定义结构锁对象ABAP数据字典概述 ABAP数据字典是SAP定义和管理数据的工具&#xff0c;包含了程序使用的所有对象&#xff0c;数据字典中包括数据库表、视图、数据类型、域、搜索帮助…

不知道Pycharm怎么安装?Pycharm安装教程(附安装包)

Pycharm安装教程&#xff08;附安装包&#xff09;获取方式&#xff1a;python开发工具包丨夸克网盘-资源免费下载 有位朋友刚开始学习python&#xff0c;不知道Pycharm要怎么安装&#xff0c;于是问我要一个安装教程。 先介绍一下Pycharm吧&#xff0c;PyCharm是一款python开…

在 Docker 容器中查看 Python 版本

博客目录前言方法一&#xff1a;交互式进入容器查看方法二&#xff1a;启动时直接执行命令方法三&#xff1a;启动后使用 exec 执行命令方法四&#xff1a;直接运行并查看版本&#xff08;容器退出&#xff09;方法比较与选择指南实际应用中的注意事项进阶技巧批量检查多个镜像…

React:Umi + React + Ant Design Pro的基础上接入Mock数据

为什么需要Mock数据 前端开发依赖后端接口时的阻塞问题 独立开发和测试的需求 快速迭代和原型验证的重要性 当前版本及框架 React18 Umi 4.0 Ant Design Ant Design Pro 其实这些都不重要&#xff0c;主要是有Umijs&#xff0c;因为Umijs具有开箱即用Mock功能的能力&#…

VMware centos磁盘容量扩容教程

目录前言相关概念磁盘磁盘分区文件系统挂载点物理卷、VG&#xff08;卷组&#xff09;、LV&#xff08;逻辑卷&#xff09;、LVM&#xff08;逻辑卷管理&#xff09;解决方案前言 这篇博客主要分享我在VM中通过docker搭建dify大模型应用平台时&#xff0c;遇到了分配的磁盘容量…

kubernetes中的认证和授权

一 kubernetes API 访问控制Authentication&#xff08;认证&#xff09;认证方式现共有8种&#xff0c;可以启用一种或多种认证方式&#xff0c;只要有一种认证方式通过&#xff0c;就不再进行其它方式的认证。通常启用X509 Client Certs和Service Accout Tokens两种认证方式。…