`
pxchen
  • 浏览: 85193 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java nio api详解(转)

阅读更多

 

JDK 1.4 以前, Java IO 操作集中在 java.io 这个包中,是基于流的阻塞( blocking API 。对于大多数应用来说,这样的 API 使用很方便,然而,一些对性能要求较高的应用,尤其是服务端应用, 往往需要一个更为有效的方式来处理 IO 。从 JDK 1.4 起, NIO API 作为一个基于缓冲区,并能 提供非阻塞 (non-blocking)IO 操作的 API 被引入。本文对其进行深入的介绍。

 

NIO API 主要集中在 java.nio 和它的 subpackages 中:

 

java.nio

定义了 Buffer 及其数据类型相关的子类。其中被 java.nio.channels 中的类用来进行 IO 操作的 ByteBuffer 的作用非常重要。

 

java.nio.channels

定义了一系列处理 IO Channel 接口以及这些接口在文件系统和网络通讯上的实现。通过 Selector 这个类,还提供了进行非阻塞 IO 操作的办法。这个包可以说是 NIO API 的核心。

 

java.nio.channels.spi

定义了可用来实现 channel selector API 的抽象类。

 

java.nio.charset

       定义了处理字符编码和解码的类。

 

java.nio.charset.spi

       定义了可用来实现 charset API 的抽象类。

 

java.nio.channels.spi java.nio.charset.spi 这 两个包主要被用来对现有 NIO API 进行扩展,在实际的使用中,我们一般只和另外的 3 个包打交道。下面将对这 3 个包一一介绍。

 

Package java.nio

这个包主要定义了 Buffer 及其子类。 Buffer 定义了一个线性存放 primitive type 数据的容器接口。对于除 boolean 以外的其他 primitive type ,都有一个相 应的 Buffer 子 类, ByteBuffer 是其中最重要的一个子类。

 

下面这张 UML 类图描述了 java.nio 中的类的关系:



 

Buffer

定义了一个可以线性存放 primitive type 数据的容器接口。 Buffer 主要包含了与类型( byte, char… )无关的功能。值得 注意的是 Buffer 及其子类都不是线程安全的。

 

每个 Buffer 都有以下的属性:

 

capacity

这个 Buffer 最多能放多少数据。 capacity 一般在 buffer 被创建的时候指定。

limit

Buffer 上进行的读写操作都不能越过这个下标。当写数据到 buffer 中时, limit 一般和 capacity 相等,当读数据时, limit 代表 buffer 中有效数据的长度。

position

/ 写操作的当前下标。当使用 buffer 的相对位置进行读 / 写操作时,读 / 写会从这个下标进行,并在操作完成后, buffer 会更新下标的值。

mark

一个临时存放的位置下标。调用 mark() 会将 mark 设为当前的 position 的值,以后调用 reset() 会将 position 属性设置为 mark 的值。 mark 的值总是小于等于 position 的值,如果将 position 的值设的比 mark 小,当前的 mark 值会被抛弃掉。

 

这些属性总是满足以下条件:

0 <= mark <= position <= limit <= capacity

 

limit position 的值除了通过 limit() position() 函数来设置,也可以通 过下面这些函数来改变:

 

Buffer clear()

position 设为 0 ,把 limit 设为 capacity ,一般在把数据写入 Buffer 前调用。

Buffer flip()

limit 设为当前 position ,把 position 设为 0 ,一般在从 Buffer 读出数据前调用。

Buffer rewind()

position 设为 0 limit 不变,一般在把数据重写入 Buffer 前调用。

 

Buffer 对象有可能是只读的,这时,任何 对该对象的写操作都会触发一个 ReadOnlyBufferException isReadOnly() 方法可以用来判断一个 Buffer 是否只读。

 

ByteBuffer

Buffer 的子类中, ByteBuffer 是一个地位较为特殊的类,因为在 java.io.channels 中定义的各种 channel IO 操作基本上都是围绕 ByteBuffer 展开的。

 

ByteBuffer 定义了 4 static 方法来做创建工作:

 

ByteBuffer allocate(int capacity)

创建一个指定 capacity ByteBuffer

ByteBuffer allocateDirect(int capacity)

创建一个 direct ByteBuffer ,这样的 ByteBuffer 在参与 IO 操作时性能会更好(很有可能是在底层的实现使用了 DMA 技术),相应的,创建和回收 direct ByteBuffer 的代价也会高一些。 isDirect() 方法可以检查一个 buffer 是否是 direct 的。

ByteBuffer wrap(byte [] array)

ByteBuffer wrap(byte [] array, int offset, int length)

把一个 byte 数组或 byte 数组的一部分包装成 ByteBuffer

 

ByteBuffer 定义了一系列 get put 操作来从中读写 byte 数据,如下面几个:

 

byte get()

ByteBuffer get(byte [] dst)

byte get(int index)

 

ByteBuffer put(byte b)

ByteBuffer put(byte [] src)

ByteBuffer put(int index, byte b)

 

这些操作可分为绝对定位和相对定为两种,相对定位的读写操作依靠 position 来定位 Buffer 中的位置,并在操作完成后会更 新 position 的 值。

在其它类型的 buffer 中,也定义了相同的函数来读写数据,唯一不同的就是一些参数和返回值的类型。

 

除了读写 byte 类型数据的函数, ByteBuffer 的一个特别之处是它还定义了读写其它 primitive 数据的方法,如:

 

int getInt()

       ByteBuffer 中读出一个 int 值。

ByteBuffer putInt(int value)

       写入一个 int 值到 ByteBuffer 中。

 

读写其它类型的数据牵涉到字节序问题, ByteBuffer 会按其字节序(大字节序或小字节序)写入或读出一个其它类型的数据( int,long… )。字节序可以用 order 方法来取得和设置:

 

ByteOrder order()

       返回 ByteBuffer 的字节序。

ByteBuffer order(ByteOrder bo)

       设置 ByteBuffer 的字节序。

 

ByteBuffer 另一个特别的地方是可以 在它的基础上得到其它类型的 buffer 。如:

 

CharBuffer asCharBuffer()

为当前的 ByteBuffer 创建一个 CharBuffer 的视图。在该视图 buffer 中的读写操作会按照 ByteBuffer 的字节序作用到 ByteBuffer 中的数据上。

 

用这类方法创建出来的 buffer 会从 ByteBuffer position 位置开始到 limit 位置结束,可以看作是这段数据的视图。视图 buffer readOnly 属性和 direct 属性与 ByteBuffer 的一致,而且也只有通过这种方法,才可以得到其他数据类型的 direct buffer

 

ByteOrder

用来表示 ByteBuffer 字节序的类,可将其看成 java 中的 enum 类型。主要定义了下面几个 static 方法和属性:

 

ByteOrder BIG_ENDIAN

       代表大字节序的 ByteOrder

ByteOrder LITTLE_ENDIAN

       代表小字节序的 ByteOrder

ByteOrder nativeOrder()

       返回当前硬件平台的字节序。

 

MappedByteBuffer

ByteBuffer 的子类,是文件内容在内 存中的映射。这个类的实例需要通过 FileChannel map() 方法来创建。

 

 

接下来看看一个使用 ByteBuffer 的例子,这个例子从标准输入不停地读入字符,当读满一行后,将收集的字符写到标准输出:

 

    public static void main(String [] args)

       throws IOException

    {

       // 创建一个 capacity 256 ByteBuffer

       ByteBuffer buf = ByteBuffer.allocate(256);

       while ( true ) {

           // 从标准输入流读入一个字符

           int c = System.in.read();

           // 当读到输入流结束时,退出循环

           if (c == -1)

              break ;

          

           // 把读入的字符写入 ByteBuffer

           buf.put(( byte ) c);

           // 当读完一行时,输出收集的字符

           if (c == '\n' ) {

              // 调用 flip() 使 limit 变为当前的 position 的值 ,position 变为 0,

              // 为接下来从 ByteBuffer 读取做准备

              buf.flip();

              // 构建一个 byte 数组

              byte [] content = new byte [buf.limit()];

              // ByteBuffer 中读取数据到 byte 数组中

              buf.get(content);

               // byte 数组的内容写到标准输出

              System.out.print( new String(content));

              // 调用 clear() 使 position 变为 0,limit 变为 capacity 的值,

              // 为接下来写入数据到 ByteBuffer 中做准备

              buf.clear();

           }

       }

    }

 

 

Package java.nio.channels

这个包定义了 Channel 的概念, Channel 表现了一个可以进行 IO 操作的通道(比如,通过 FileChannel ,我们可以对文件进行读写操作)。 java.nio.channels 包含了文件系统和网络通讯相关的 channel 类。这个包通过 Selector SelectableChannel 这两个类,还定义了一个进行非阻塞( non-blocking IO 操作的 API ,这对需要高性能 IO 的应用非常重要。

 

下面这张 UML 类图描述了 java.nio.channels interface 的关系:

 



 

Channel

Channel 表现了一个可以进行 IO 操作的通道,该 interface 定义了以下方法:

 

boolean isOpen()

       Channel 是否是打开的。

void close()

       关闭这个 Channel ,相关的资源会被释放。

 

ReadableByteChannel

定义了一个可从中读取 byte 数据的 channel interface

 

int read(ByteBuffer dst)

channel 中读取 byte 数据并写到 ByteBuffer 中。返回读取的 byte 数。

 

WritableByteChannel

定义了一个可向其写 byte 数据的 channel interface

 

int write(ByteBuffer src)

       ByteBuffer 中读取 byte 数据并写到 channel 中。返回写出的 byte 数。

 

ByteChannel

ByteChannel 并没有定义新的方法, 它的作用只是把 ReadableByteChannel WritableByteChannel 合并在一起。

 

ScatteringByteChannel

继承了 ReadableByteChannel 并提供了同时往几个 ByteBuffer 中写数据的能力。

 

GatheringByteChannel

继承了 WritableByteChannel 并提供了同时从几个 ByteBuffer 中读数据的能力。

 

InterruptibleChannel

用来表现一个可以被异步关闭的 Channel 。这表现在两方面:

1.    当一个 InterruptibleChannel close() 方法被调用时,其它 block 在这个 InterruptibleChannel IO 操作上的线程会接收到一个 AsynchronousCloseException

2.    当一个 线程 block InterruptibleChannel IO 操作上时,另一个线程调用该线程的 interrupt() 方法会导致 channel 被关闭,该线程收到一个 ClosedByInterruptException ,同时线程的 interrupt 状态会被设置。

 

 

接下来的这张 UML 类图描述了 java.nio.channels 中类的关系:

 



 

非阻塞 IO

非阻塞 IO 的支持可以算是 NIO API 中最重要的功能,非阻塞 IO 允许应用程序同时监控多个 channel 以提高性能,这一功能是通过 Selector SelectableChannel SelectionKey 3 个类来实现的。

 

SelectableChannel 代表了可 以支持非阻塞 IO 操 作的 channel , 可以将其注册在 Selector 上,这种注册的关系由 SelectionKey 这个类来表现(见 UML 图)。 Selector 这个类通过 select() 函数,给应用程序提供了一个可以同时监控多个 IO channel 的方法:

 

应用程序通过调用 select() 函数,让 Selector 监控注册在其上的多个 SelectableChannel ,当有 channel IO 操作可以进行时, select() 方法就会返回以让应用程序检查 channel 的状态,并作相应的处理。

 

下面是 JDK 1.4 中非阻塞 IO 的一个例子,这段 code 使用了非阻塞 IO 实现了一个 time server

 

    private static void acceptConnections( int port) throws Exception {

       // 打开一个 Selector

       Selector acceptSelector =

           SelectorProvider.provider().openSelector();

 

       // 创建一个 ServerSocketChannel ,这是一个 SelectableChannel 的子类

       ServerSocketChannel ssc = ServerSocketChannel.open();

       // 将其设为 non-blocking 状态,这样才能进行非阻塞 IO 操作

       ssc.configureBlocking( false );

 

margin: 0cm 0cm 0pt; text-align: le

分享到:
评论

相关推荐

    【创新未发表】Matlab实现花朵授粉优化算法FPA-Kmean-Transformer-BiLSTM负荷预测算法研究.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    综合糖尿病健康数据集.zip

    ## **背景描述** 糖尿病是一种影响全球数百万人的慢性疾病,对公共健康构成重大威胁。准确预测糖尿病的发病风险对于早期干预和预防至关重要。通过机器学习模型分析影响糖尿病的主要因素,可以帮助医疗从业者更好地了解病因和风险因素,从而制定有效的预防和治疗策略。 本数据集来自Kaggle,包含了患者的各项健康指标及其是否患有糖尿病的标签。数据集的主要目标是通过机器学习模型预测糖尿病的发病风险,并分析影响糖尿病的主要健康因素。 ## **数据说明** | 字段名 | 说明 | | --- | --- | | PatientID | 患者ID | | Age | 年龄(岁) | | Gender | 性别,0:男,1:女 | | Ethnicity | 种族,0:白种人,1:非裔美国人,2:亚洲人,3:其他| | SocioeconomicStatus | 社会经济地位,0:低,1:中,2:高 | | EducationLevel | 教育水平,0:无,1:高中,2:学士学位,3:更高 | | BMI | 体质指数(体重(kg)/身高(m)^2) | | Smoking | 吸烟状况 |

    端口扫面软件,自动检索出服务器开放的所有端口

    端口扫面软件,自动检索出服务器开放的所有端口

    基于Node.js与Vue.js的综合性项目设计源码

    该项目是一款基于Node.js和Vue.js构建的综合型项目源码,涉及207个文件,包括110个PNG图片、53个Vue组件、16个JavaScript文件、7个JSON配置、5个SCSS样式、4个JPG图片、2个文本文件、1个Git忽略规则文件、1个许可证文件和1个Markdown描述文件。

    【发文无忧】基于凌日优化算法TSOA-Kmean-Transformer-GRU实现数据回归预测算法研究Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    梦幻西游道人20241106f

    梦幻西游道人是梦幻西游里面的一个NPC,主要是刷全服最实惠的高级兽决和其他很好用的比较贵的东西,在长安城、傲来国、长寿村中的任意一个场景出现,一般会出现30分钟,不过东西一般都被秒刷。 梦幻西游道人出现时间解析如下: 1.梦幻西游道人出现时间一直都保持着一年出现两次的规律,即2、3月份的元宵节期间来一次,9月份的教师节期间出现一次。 2.云游道人每个整点(0:00至7:00不出现)会在长安城、傲来国、长寿村中的任意一个场景出现,每次出现后停留时间为30分钟。

    【创新未发表】Matlab实现雪融优化算法SAO-GRU实现风电数据预测算法研究.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    暴风电视刷机数据 55R5 屏LC550EGY-SJM2 机编60000AM0S00 屏参30173304 V4.0.43版本

    2G+16G主程序物料号11173101 AML-962H机芯升级步骤 本地升级: 1、将2G+xG_update.zip重命名update.zip,拷贝至U盘,插入电视USB,打开电视进入设置 2、选择本地升级,升级完毕后电视会重启,操作过程中切勿断电关机 升级完成后可以在系统设置——本机信息——查询软件版本 强制升级: 1、解压强制升级脚本recovery.img与factory_update_param.aml,加上update.zip三个文件拷贝至U盘根目录,插入电视USB 2、插拔下电源,按遥控器待机键后快速不停点按遥控器右键5-10下触发主板识别U盘软件进行升级 3、升级完毕后电视会重启,操作过程中切勿断电关机 串口升级 1、将三个升级软件拷贝至U盘根目录下,然后插入电视的USB接口 2、电视开启的时候按住电脑键盘Enter回车键出现txl_p392_v1#时,输入run update敲回车,系统识别U盘软件进行升级 如未成功先确认输入指令是否正常,reboot重新启动再试 若还是无法升级可能是硬件存储系统的EMMC模块损坏,请更换主板

    计算机图形学之动画和模拟算法:流体模拟中的物理约束.docx

    计算机图形学之动画和模拟算法:流体模拟中的物理约束.docx

    jjjgbdfgdsfgsdggdfsdgf

    jjjgbdfgdsfgsdggdfsdgf

    基于SSM框架+jsp+mysql实现的精准扶贫信息综合平台前台管理系统【源码+数据库】

    一、项目简介 本项目是一套基于SSM框架扶贫信息综合平台前台管理系统,主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本等,该项目附带全部源码可作为毕设使用。 项目都经过严格调试,eclipse 确保可以运行! 该系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值 二、技术实现 spring+springmvc+mybatis+jsp+jquery+css 三、开发运行环境 jdk1.8 Tomcat8及其以上版本 Mysql5.5及以上版本 四、系统功能 系统分为两种用户:管理员,普通用户 前台功能: 首页 个人中心 用户登录 用户注册 政策信息:政策列表信息,浏览量 发布评论 推荐文章 最新评论文章 按关键字全局搜索文章 先进事例 下乡信息 后台功能: 用户管理 系统日志管理 文章管理 评论管理、文章分类 文章统计 人口管理 系统设置等功能 详见 https://blog.csdn.net/weixin_43860634/article/details/130546247

    supermario!

    supermario!

    计算机图形学之动画和模拟算法:流体模拟的优化与并行计算.docx

    计算机图形学之动画和模拟算法:流体模拟的优化与并行计算.docx

    八上期中复习音频.zip

    八上期中复习音频.zip

    weixin049基于微信小程序校园外卖平台设计与实现+ssm后端毕业源码案例设计.zip

    weixin049基于微信小程序校园外卖平台设计与实现+ssm后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。

    安卓仿微信联系人右侧导航栏滑动联动效果

    安卓 仿微信联系人,通讯录,右侧字母导航栏滑动联系人联动效果

    实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip

    实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip,含有代码注释,新手也可看懂,个人手打98分项目,导师非常认可的高分项目,毕业设计、期末大作业和课程设计高分必看,下载下来,简单部署,就可以使用。该项目可以直接作为毕设、期末大作业使用,代码都在里面,系统功能完善、界面美观、操作简单、功能齐全、管理便捷,具有很高的实际应用价值,项目都经过严格调试,确保可以运行! 实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实战项目-使用支持向量机(SVM)算法进行人脸识别源码.zip实

    计算机图形学之动画和模拟算法:Cloth Simulation:离散动力学系统.docx

    计算机图形学之动画和模拟算法:Cloth Simulation:离散动力学系统

    【光伏预测】基于白鲨优化算法WSO优化高斯过程回归GPR实现光伏多输入单输出预测附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。 替换数据可以直接使用,注释清楚,适合新手

    暴风电视刷机数据 58R5 屏V580DJ4-QE1 机编60000MM0U00 屏参30173403 V1.0.74版本

    2G+16G主程序物料号11173101 AML-962H机芯升级步骤 本地升级: 1、将2G+xG_update.zip重命名update.zip,拷贝至U盘,插入电视USB,打开电视进入设置 2、选择本地升级,升级完毕后电视会重启,操作过程中切勿断电关机 升级完成后可以在系统设置——本机信息——查询软件版本 强制升级: 1、解压强制升级脚本recovery.img与factory_update_param.aml,加上update.zip三个文件拷贝至U盘根目录,插入电视USB 2、插拔下电源,按遥控器待机键后快速不停点按遥控器右键5-10下触发主板识别U盘软件进行升级 3、升级完毕后电视会重启,操作过程中切勿断电关机 串口升级 1、将三个升级软件拷贝至U盘根目录下,然后插入电视的USB接口 2、电视开启的时候按住电脑键盘Enter回车键出现txl_p392_v1#时,输入run update敲回车,系统识别U盘软件进行升级 如未成功先确认输入指令是否正常,reboot重新启动再试 若还是无法升级可能是硬件存储系统的EMMC模块损坏,请更换主板

Global site tag (gtag.js) - Google Analytics