一、概述

从JDK1.4开始,Java提供了一系列改进的输入/输出处理的新特性,被统称为NIO(即New I/O)。新增了许多用于处理输入输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写,新增了满足NIO的功能。NIO采用内存映射文件的方式来处理输入输出,NIO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样访问文件了。

NIO 与原来的 I/O 有同样的作用和目的,但是它使用不同的方式?  块I/O。块 I/O 的效率可以比流 I/O 高许多。

流与块的比较

原来的 I/O 库(在 java.io.*中) 与 NIO 最重要的区别是数据打包和传输的方式。正如前面提到的,原来的 I/O 以流的方式处理数据,而 NIO 以块的方式处理数据。

面向流 的 I/O 系统一次一个字节地处理数据。一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。为流式数据创建过滤器非常容易。链接几个过滤器,以便每个过滤器只负责单个复杂处理机制的一部分,这样也是相对简单的。不利的一面是,面向流的 I/O 通常相当慢。

一个 面向块 的 I/O 系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按(流式的)字节处理数据要快得多。但是面向块的 I/O 缺少一些面向流的 I/O 所具有的优雅性和简单性。

在NIO中有几个核心对象需要掌握:缓冲区(Buffer)、通道(Channel)、选择器(Selector)。

二、缓冲区Buffer

缓冲区实际上是一个容器对象,更直接的说,其实就是一个数组,在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流I/O系统中,所有数据都是直接写入或者直接将数据读取到Stream对象中。具体看下面这张图就理解了:

上面的图描述了从一个客户端向服务端发送数据,然后服务端接收数据的过程。客户端发送数据时,必须先将数据存入Buffer中,然后将Buffer中的内容写入通道。服务端这边接收数据必须通过Channel将数据读入到Buffer中,然后再从Buffer中取出数据来处理。

在NIO中,所有的缓冲区类型都继承于抽象类Buffer,最常用的就是ByteBuffer,对于Java中的基本类型,基本都有一个具体Buffer类型与之相对应,它们之间的继承关系如下图所示:

下面是一个简单使用IntBuffer的例子:

package com.demo.nio;

import java.nio.IntBuffer;

public class TestIntBuffer {

public static void main(String[] args) {

// 分配新的int缓冲区,参数为缓冲区容量

// 新缓冲区的当前位置将为零,其界限(限制位置)将为其容量。它将具有一个底层实现数组,其数组偏移量将为零。

IntBuffer buffer = IntBuffer.allocate(8);

for (int i = 0; i < buffer.capacity(); ++i) {

int j = 2 * (i + 1);

// 将给定整数写入此缓冲区的当前位置,当前位置递增

buffer.put(j);

}

// 重设此缓冲区,将限制设置为当前位置,然后将当前位置设置为0

buffer.flip();

// 查看在当前位置和限制位置之间是否有元素

while (buffer.hasRemaining()) {

// 读取此缓冲区当前位置的整数,然后当前位置递增

int j = buffer.get();

System.out.print(j + " ");

}

}

}

运行后可以看到:

三、通道Channel

Channel和传统IO中的Stream很相似。虽然很相似,但是有很大的区别,主要区别为:通道是双向的,通过一个Channel既可以进行读,也可以进行写;而Stream只能进行单向操作,通过一个Stream只能进行读或者写,比如InputStream只能进行读取操作,OutputStream只能进行写操作;

通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

在NIO中,提供了多种通道对象,而所有的通道对象都实现了Channel接口。它们之间的继承关系如下图所示:

Channel(通道)表示到实体如硬件设备、文件、网络套接字或可以执行一个或多个不同I/O操作的程序组件的开放的连接。所有的Channel都不是通过构造器创建的,而是通过传统的节点InputStream、OutputStream的getChannel方法来返回响应的Channel。

Channel中最常用的三个类方法就是map、read和write,其中map方法用于将Channel对应的部分或全部数据映射成ByteBuffer,而read或write方法有一系列的重载形式,这些方法用于从Buffer中读取数据或向Buffer中写入数据。

1、使用NIO读取数据

在前面我们说过,任何时候读取数据,都不是直接从通道读取,而是从通道读取到缓冲区。所以使用NIO读取数据可以分为下面三个步骤:(1). 从FileInputStream获取Channel(2). 创建Buffer(3). 将数据从Channel读取到Buffer中

下面是一个简单的使用NIO从文件中读取数据的例子:

import java.io.*;

import java.nio.*;

import java.nio.channels.*;

public class Program {

public static void main( String args[] ) throws Exception {

FileInputStream fin = new FileInputStream("c:\\test.txt");

// 获取通道

FileChannel fc = fin.getChannel();

// 创建缓冲区

ByteBuffer buffer = ByteBuffer.allocate(1024);

// 读取数据到缓冲区

fc.read(buffer);

buffer.flip();

while (buffer.remaining()>0) {

byte b = buffer.get();

System.out.print(((char)b));

}

fin.close();

}

}

2、使用NIO写入数据

使用NIO写入数据与读取数据的过程类似,同样数据不是直接写入通道,而是写入缓冲区,可以分为下面三个步骤:

(1). 从FileInputStream获取Channel

(2). 创建Buffer

(3). 将数据从Channel写入到Buffer中

下面是一个简单的使用NIO向文件中写入数据的例子:

package com.demo.nio;

import java.io.FileOutputStream;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

public class Program {

private static final byte message[] = { 83, 111, 109, 101, 32,

98, 121, 116, 101, 115, 46 };

public static void main( String args[] ) throws Exception {

FileOutputStream fout = new FileOutputStream( "c:\\test.txt" );

FileChannel fc = fout.getChannel();

ByteBuffer buffer = ByteBuffer.allocate( 1024 );

for (int i=0; i

buffer.put( message[i] );

}

buffer.flip();

fc.write( buffer );

fout.close();

}

}

四、选择器Selector

Selector类是NIO的核心类,Selector能够检测多个注册的通道上是否有事件发生,如果有事件发生,便获取事件然后针对每个事件进行相应的响应处理。这样一来,只是用一个单线程就可以管理多个通道,也就是管理多个连接。这样使得只有在连接真正有读写事件发生时,才会调用函数来进行读写,就大大地减少了系统开销,并且不必为每个连接都创建一个线程,不用去维护多个线程,并且避免了多线程之间的上下文切换导致的开销。

与Selector有关的一个关键类是SelectionKey,一个SelectionKey表示一个到达的事件,这2个类构成了服务端处理业务的关键逻辑。

java nio nio2 区别_Java NIO2:NIO概述相关推荐

  1. java io流区别_Java中IO流的分类和BIO,NIO,AIO的区别

    到底什么是IO 我们常说的IO,指的是文件的输入和输出,但是在操作系统层面是如何定义IO的呢?到底什么样的过程可以叫做是一次IO呢? 拿一次磁盘文件读取为例,我们要读取的文件是存储在磁盘上的,我们的目 ...

  2. java io和nio的区别_Java中IO和NIO的本质和区别

    导读热词 简介 终于要写到java中最最让人激动的部分了IO和NIO.IO的全称是input output,是java程序跟外部世界交流的桥梁,IO指的是java.io包中的所有类,他们是从java1 ...

  3. java reactor模式例子_JAVA BIO,NIO,Reactor模式总结

    传统同步阻塞I/O(BIO) 在NIO之前编写服务器使用的是同步阻塞I/O(Blocking I/O).下面是一个典型的线程池客服端服务器示例代码,这段代码在连接数急剧上升的情况下,这个服务器代码就会 ...

  4. java nio拷贝文件_Java 7 – NIO文件革命

    java nio拷贝文件 Java 7("项目代币")已于去年7月问世. 此版本中的新增功能很有用,例如,尝试资源-从try块中自动处理可关闭的资源,switch语句中的字符串,用 ...

  5. nio tcp 释放_java socket nio 运行时间久 有掉包现象 而且 运行 缓慢

    匿名用户 1级 2016-11-01 回答 套接字或插座(socket)是一种软件形式的抽象,用于表达两台机器间一个连接的"终端".针对一个特定的连接,每台机器上都有一个" ...

  6. java c++的区别_Java语言与C、C++之间的区别?

    小伙伴你知道吗?Java是由C++开发而来的,并且在当时一直被搁置.随着Java语言的崛起那么Java和C/C++有什么不同和相同之处呢? 通过上述我们知道那Java前身是C++,并且保留了C++的大 ...

  7. java 反射 new区别_JAVA的newInstance()和new的区别(JAVA反射机制,通过类名来获取该类的实例化对象)...

    1.在初始化一个类,生成一个实例的时候:newInstance() 和 new 有什么区别? 用newInstance与用new是区别的,区别在于创建对象的方式不一样,前者是使用类加载机制,那么为什么 ...

  8. java 前后的区别_java中前后++的区别

    java中前后++的区别 发布时间:2020-06-22 14:38:22 来源:亿速云 阅读:134 作者:Leah 这篇文章将为大家详细讲解有关java中前后++的区别,小编觉得挺实用的,因此分享 ...

  9. java web 许令波_Java Web——Web概述

    已经很久没有更新博客了,过年忙着吃喝玩乐,就怠惰了一小下下?幸好这学期新开的课程都比较有趣--Java Web和Android.至少对于我自己来说,既充满挑战,又富有趣味. --[1.Web概述]-- ...

最新文章

  1. [LeetCode]202. Happy Number(平衡二叉树 哈希表)
  2. 维纳滤波原理(Wiener Filter)
  3. 听说这里有让你膜拜的产品方法论?
  4. BZOJ 4734 UOJ #269 [清华集训2016]如何优雅地求和 (多项式)
  5. 核桃编程 | 前端可观测性建设之路
  6. Spring Boot 动态数据源(Spring 注解数据源)
  7. abstract类_【Java】类的结构 - Nemo
  8. [html] 制作一个多选的下拉框
  9. 易语言python1.1模块_易语言之编写模块与引入模块
  10. ORACLE与PostgreSql的区别
  11. flex4.5新特征
  12. python3 ImageTk 安装方法
  13. 手机计算机图标大全,我的电脑里我的手机图标怎么删除
  14. 加一(Java求解)
  15. 移动端 --- 解决苹果手机滑动卡顿的问题
  16. Oracle索引和事务
  17. 阿里云新年活动 轻量云服务器1H2G5M仅需要86元/年
  18. pygame 实现键盘鼠标映射
  19. golang 撤回_Activiti6.0版本流程撤回、跳转、回退等操作
  20. 组合数学——牡牛和牝牛

热门文章

  1. 【剑道之道】亦是生存之道
  2. 捕捉mysql中不可忽视的知识点(二)
  3. C# DllImport
  4. linux无人值守安装
  5. struct tm 和 time_t
  6. 数据结构及算法基础--优先队列(Priority Queue)
  7. cxf 整合 spring 时 java.lang.VerifyError异常
  8. Win32API 窗口程序的创建7大步骤
  9. CBV 验证装饰器的使用
  10. 师生对话:我们都曾是爱学习的孩子