NIO概述

从JDK1.4开始,引入了新的I/O类库,它们位于java.nio包中,其目的在于提高I/O的操作效率。nio是new io的缩写。

参考文章:NIO BIO AIO区别

java.nio包引入了四个关键的数据类型:

  • Buffer:缓冲区,临时存放输入或输出数据。
  • Charset:把具有Unicode字符串编码转换为其他字符编码,以及把其他字符编码转换为Unicode编码的功能。
  • Channel:数据传输管道。能够把Buffer中的数据写到数据汇,或者把数据源的数据读到Buffer。NIO基于Channel和Buffer操作,数据总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中。
  • Selector:支持异步I/O操作,也称为非阻塞I/O操作。Selector用于监听多个信道事件(比如链接打开,数据到达等)使得单线程可以监听多个数据的信道

缓冲器Buffer概述

数据输入和输出往往是比较耗时的操作。缓冲区从两个方面提高I/O的操作效率

  • 减少实际的物理读写次数
  • 缓冲区在创建时被分配内存,这块内存一直被重用,这可以减少动态分配和回收内存区域的次数

旧IO类库中的BufferInputStream BufferOutStream BufferReader BufferWriter在实现中都运用了缓冲区。新I/O包公开了Buffer API,使得程序可以直接控制和运用缓冲区

所有缓冲区都有以下属性。

  • 容量:表示缓冲区可以保存多少数据。
  • 极限:表示缓冲区的当前终点,不能对缓冲区中超过极限的数据进行读写操作。极限值是可以修改的,这有利于缓冲区的重用。

列如 假定容量为100的缓冲区已经填满了数据,接着程序在重用缓冲区时,仅仅将十个新的数据写入缓冲区,这样时可以将极限值设置为10,这样就不能访问先前的数据。

极限值是一个非负整数值,不应该大于容量值。

  • 位置:表示缓冲区下一个读写单元的位置,每次读写缓冲区的数据时,都会改变该值,为下一次读写数据做准备。位置是一个非负整数值,不应该大于容量值。

以上三个属性的关系为 容量≥极限 ≥位置 ≥0

缓冲区提供了用于改变以上三个属性的方法。

  • clear() 使缓冲区为一系列新的通道读取或相对放置 操作做好准备:它将极限设置为容量大小,将位置设置为 0。

  • flip() 使缓冲区为一系列新的通道写入或相对获取 操作做好准备:它将极限设置为当前位置,然后将位置设置为 0。

  • rewind() 使缓冲区为重新读取已包含的数据做好准备:它使极限保持不变,将位置设置为 0。

Channel概述

通过Channel用来连接缓冲区与数据源或数据汇。数据源的数据经过通道到达缓冲区,缓冲区的数据经过通道到达数据汇。

中文意思“通道”,表示IO源与目标打开的连接,类似于传统的“流”(通道与流的不同之处在于通道是双向的)。但是Channel不能直接访问数据,

Channel最重要的两个接口ReadableByteChannelWritableByteChannel。ReadableByteChannel声明了read(ByteBuffer dst)方法,该方法把数据源的数据读入到指定的ByteBuffer缓冲区中。

FileChannel是Channel接口的实现类,代表与一个文件相连的通道FileChannel类没有提供公开的构造方法,因此客户程序不能用new语句来构造它的实例。

不过,在FileInputStream FileOutputStream类中提供了getChannel()方法,该方法返回相应的FileChannel对象。

字符编码Charset概述

Charset类的每个实例代表指定的字符编码类型,提供了以下用于编码转换的方法。(把Charset对象表示的字符编码简称为当前字符编码)

     把参数str指定的字符串转换为当前字符的编码,把转换后的当前字符编码存放在一个ByteBuffer对象中,并将其返回。

    把参数cb指定的字符缓冲区中的字符转换为当前字符的编码,把转换后的当前字符编码存放在一个ByteBuffer对象中,并将其返回。原先参数cb缓冲区内的字符使用Unicode编码。

     把参数指定的ByteBuffer中的当前字符编码转换为Unicode编码,把转换后的Unicode编码存放在一个CharBuffer对象中,将其返回。

参考文章:java基本数据类型

Selector

1)多路复用器(Selector),他是NIO编程的基础,非常重要。多路复用器提供选择已经就绪的任务的能力。

2)简单说,就是Selector会不断地轮询注册在其上的通道(Channel),如果某个通道发生了读写操作,这个通道就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以取得就绪的Channel集合,从而进行后续的IO操作。

3)一个多路复用器(Selector)可以负责成千上万Channel通道,没有上限,这也是JDK使用了epoll代替了传统的select实现,获得连接句柄没有限制。这也就意味着我们只要一个线程负责Selector的轮询,就可以接入成千上万个客户端,这是JDK NIO库的巨大进步。

4)Selector线程就类似一个管理者(Master),管理了成千上万个管道,然后轮询那个管道的数据已经准备好,通知cpu执行IO的读取或写入操作。

5)Selector模式:当IO事件(管道)注册到选择器以后,selector会分配给每个管道一个key值,相当于标签。selector选择器是以轮询的方式进行查找注册的所有IO事件(管道),当我们的IO事件(管道)准备就绪后,select就会识别,会通过key值来找到相应的管道,进行相关的数据处理操作(从管道里读或写数据,写到我们的数据缓冲区中)。

利用FileChannel读写文件

public class FileChannelTester {
public static void main(String[] args) throws Exception {
final int size = 1024;
final String path = "D:\\test.txt";
//向文件中写数据
FileChannel fc = new FileOutputStream(path).getChannel();
fc.write(ByteBuffer.wrap("你好,".getBytes()));
fc.close();
//向文件末尾添加数据
fc= new RandomAccessFile(path,"rw").getChannel();
fc.position(fc.size());
fc.write(ByteBuffer.wrap("朋友!".getBytes()));
fc.close();
//读数据
fc = new FileInputStream(path).getChannel();
ByteBuffer buff = ByteBuffer.allocate(size);
fc.read(buff);
buff.flip();
Charset cs = Charset.defaultCharset();
System.out.println(cs.decode(buff));
fc.close();
}
}
  • 在上面main()方法中,先从文件输出流中得到一个FileChannel对象,然后通过它把ByteBuffer对象中的数据写到文件中。

    "你好,".getBytes()使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。ByteBuffer类的wrap(byte[])把一个字节数组包装成一个ByteBuffer对象。

  • main()方法接着从RandomAccessFile对象中得到一个FileChannel对象,定位到文件末尾,然后向文件中写入字符串"朋友!",该字符串仍然采用本地平台的字符编码。
  • main()方法接着从文件输入了中得到一个FileChannel对象,然后调用ByteBuffer.allocate()方法创建了一个ByteBuffer对象 容量为1024个字节。

    fc.read(buff)方法把文件中的数据读入到ByteBuffer中。接下来buff.flip()方法把缓冲区的极限limit设置为当前位置,

在把position设为0,这使得接下来的cs.decode(buff)方法仅仅操作刚刚写入缓冲区的数据。cs.decode()方法把缓冲区的数据转换为Unicode编码,然后打印该编码所代表的字符串。以上程序打印结果为"你好,朋友!"

NIO类库的更多相关文章

  1. Java NIO类库Selector机制解析(上)

    一.  前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...

  2. Java NIO类库Selector机制解析--转

    一.  前言 自从J2SE 1.4版本以来,JDK发布了全新的I/O类库,简称NIO,其不但引入了全新的高效的I/O机制,同时,也引入了多路复用的异步模式.NIO的包中主要包含了这样几种抽象数据类型: ...

  3. JAVA NIO 类库的异步通信框架netty和mina

    Netty 和 Mina 我究竟该选择哪个? 根据我的经验,无论选择哪个,都是个正确的选择.两者各有千秋,Netty 在内存管理方面更胜一筹,综合性能也更优.但是,API 变更的管理和兼容性做的不是太 ...

  4. Java NIO类库Selector机制解析(下)

    五.  迷惑不解 : 为什么要自己消耗资源? 令人不解的是为什么我们的Java的New I/O要设计成这个样子?如果说老的I/O不能多路复用,如下图所示,要开N多的线程去挨个侦听每一个Channel ...

  5. NIO初识

    Java编程中的NIO,俗称new I/O,是在JDK1.4版本之后开始引入的,在JDK1.4之前,Java服务端大多使用同步阻塞式来处理网络请求,在低流量.低并发情况还能抗住,在如今互联网时代,信息 ...

  6. 第二章 NIO入门

    传统的同步阻塞式I/O编程 基于NIO的非阻塞编程 基于NIO2.0的异步非阻塞(AIO)编程 为什么要使用NIO编程 为什么选择Netty 第二章 NIO 入门 2.1 传统的BIO编程 2.1.1 ...

  7. Java NIO 基础

    Java在JDK1.4中引入了 java.nio 类库,为Java进军后端Server和中间件开发打开了方便之门. 一般而言,这里的 nio 代表的是 New I/O,但是从实质上来说,我们可以将其理 ...

  8. JDK NIO编程

    我们首先需要澄清一个概念:NIO到底是什么的简称?有人称之为New I/O,因为它相对于之前的I/O类库是新增的,所以被称为New I/O,这是它的官方叫法.但是,由于之前老的I/O类库是阻塞I/O, ...

  9. Java NIO服务器端开发

    一.NIO类库简介 1.缓冲区Buffer Buffer是一个对象,包含一些要写入和读出的数据. 在NIO中,所有的数据都是用缓冲区处理的,读取数据时,它是从通道(Channel)直接读到缓冲区中,在 ...

随机推荐

  1. 九 Jenkins持续集成

    随时随地将代码合并的方法叫做 持续集成 =================================================================== 视频用的10.0.0.1 ...

  2. python-装饰器&生成器&迭代器&推导式

    一:普通装饰器 概念:在不改变原函数内部代码的基础上,在函数执行之前和之后自动执行某个功能,为已存在的对象添加某个功能 普通装饰器编写的格式 def 外层函数(参数) def 内层函数(*args,* ...

  3. Spring boot 学习笔记 1 - 自定义错误

    Spring Boot提供了WebExceptionHandler一个以合理的方式处理所有错误的方法.它在处理顺序中的位置就在WebFlux提供的处理程序之前,这被认为是最后一个处理程序. 对于机器客 ...

  4. Log4j使用笔记:每天生成一个日志文件、按日志大小生成文件

    其中TestLog4j.java如下: package cn.zhoucy.test; import org.apache.log4j.Logger; public class TestLog4j { ...

  5. nginx学习.第一部分

    1.nginx的版本发布历史 2015年支持thread pool提供stream四层反向代理支持reuseport特性,支持http v2协议.完全可以替代LVS 2016年支持动态模块 2.ngi ...

  6. 今日报错Cannot access java.lang.String

    public java.long.Long getId() { return id; } public void setId(java.lang.Long id) { this.id = id;} 手 ...

  7. JAVA注释--2019-04-28

    一.JAVA自带注解 1.@Override:覆盖父类方法 2.@Deprecated:不建议使用(就是方法上画一条横线划掉那种) 3.@SuppressWarnings:去掉警告:使用方法:@Sup ...

  8. Unreal 4 error 记录

    1.打包出来的exe,黑屏 这种最大的可能是在“地图&模式中”将 Default Maps设置为自己的map,注意这里分为Editor Startup Map和Game Default Map ...

  9. 用Sklearn画一颗决策树

    小伙伴们大家好~o( ̄▽ ̄)ブ,首先声明一下,我的开发环境是Jupyter lab,所用的库和版本大家参考: Python 3.7.1(你的版本至少要3.4以上 Scikit-learn 0.20.0 ...

  10. python_非阻塞套接字及I/O流

    http://www.cnblogs.com/lixy-88428977/p/9638949.html 首先,我们要明确2个问题: 普通套接字实现的服务端有什么缺陷吗? 有,一次只能服务一个客户端! ...