在JDK1.4以前,I/O输入输出处理,我们把它称为旧I/O处理,在JDK1.4开始,java提供了一系列改进的输入/输出新特性,这些功能被称为新I/O(NEW I/O),新添了许多用于处理输入/输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类以NIO为基础进行了改写,新添了满足新I/O的功能。

Java NIO和IO的主要区别

IO

NIO

面向流

面向缓冲

阻塞IO

非阻塞IO

选择器

面向缓冲(Buffer)

在整个Java的心I/O中,所以操作都是以缓冲区进行的,使操作的性能大大提高。

操作

在Buffer中存在一系列的状态变量,这状态变量随着写入或读取都可能会被概念,在缓冲区开元使用是三个值表示缓冲区的状态。

position:表示下个缓冲区读取或写入的操作指针,没向缓冲区中华写入数据的时候 此指针就会改变,指针永远放在写入的最后一个元素之后。即:如果写入了4个位置的数据,则posotion会指向第5个位置。

Limit:表示还有多少数据可以存储或读取,position<=limit

capacity:表示缓冲区的最大容量,limit<=capacity,此值在分配缓冲区时被设置。一般不改变。

创建缓冲区:

importjava.nio.IntBuffer ;public classIntBufferDemo{public static voidmain(String args[]){

IntBuffer buf= IntBuffer.allocate(10) ; //准备出10个大小的缓冲区

System.out.print("1、写入数据之前的position、limit和capacity:") ;

System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " +buf.capacity()) ;int temp[] = {5,7,9} ;//定义一个int数组

buf.put(3) ; //设置一个数据

buf.put(temp) ; //此时已经存放了四个记录

System.out.print("2、写入数据之后的position、limit和capacity:") ;

System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " +buf.capacity()) ;

buf.flip() ;//重设缓冲区//postion = 0 ,limit = 原本position

System.out.print("3、准备输出数据时的position、limit和capacity:") ;

System.out.println("position = " + buf.position() + ",limit = " + buf.limit() + ",capacty = " +buf.capacity()) ;

System.out.print("缓冲区中的内容:") ;while(buf.hasRemaining()){int x =buf.get() ;

System.out.print(x+ "、") ;

}

}

}

如果创建了缓冲区,则JVM可直接对其执行本机的IO操作

importjava.nio.ByteBuffer ;public classByteBufferDemo{public static voidmain(String args[]){

ByteBuffer buf= ByteBuffer.allocateDirect(10) ; //准备出10个大小的缓冲区

byte temp[] = {1,3,5,7,9} ; //设置内容

buf.put(temp) ; //设置一组内容

buf.flip() ;

System.out.print("主缓冲区中的内容:") ;while(buf.hasRemaining()){int x =buf.get() ;

System.out.print(x+ "、") ;

}

}

}

通道(Channel)

Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

Java NIO的通道类似流,但又有些不同:

既可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的。

通道可以异步地读写。

通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。

正如上面所说,从通道读取数据到缓冲区,从缓冲区写入数据到通道。

Channel的实现

这些是Java NIO中最重要的通道的实现:

FileChannel

DatagramChannel

SocketChannel

ServerSocketChannel

FileChannel 从文件中读写数据。

DatagramChannel 能通过UDP读写网络中的数据。

SocketChannel 能通过TCP读写网络中的数据。

ServerSocketChannel可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

通过通道可以完成双向的输入和输出操作。在通道还有一种方式称为内存映射

几种读入的方式的比较

RandomAccessFile 较慢

FileInputStream 较慢

缓冲读取      速度较快

内存映射      速度最快

FileChannel内存映射实例

importjava.nio.ByteBuffer ;importjava.nio.MappedByteBuffer ;importjava.nio.channels.FileChannel ;importjava.io.File ;importjava.io.FileOutputStream ;importjava.io.FileInputStream ;public classFileChannelDemo03{public static void main(String args[]) throwsException{

File file= new File("d:" + File.separator + "oumyye.txt") ;

FileInputStream input= null;

input= newFileInputStream(file) ;

FileChannel fin= null ; //定义输入的通道

fin = input.getChannel() ; //得到输入的通道

MappedByteBuffer mbb = null;

mbb= fin.map(FileChannel.MapMode.READ_ONLY,0,file.length()) ;byte data[] = new byte[(int)file.length()] ; //开辟空间接收内容

int foot = 0;while(mbb.hasRemaining()){

data[foot++] = mbb.get() ; //读取数据

}

System.out.println(new String(data)) ; //输出内容

fin.close() ;

input.close() ;

}

}

操作以上代码的时候,执行的是写入操作则可能是非常危险的,因为仅仅只是改变数组中的单个元素这种简单的操作,就可能直接修改磁盘上的文件,因为修改数据与数据保存在磁盘上是一样的。

选择器(Selectors)

Selector(选择器)是Java NIO中能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。

为什么使用Selector?

仅用单个线程来处理多个Channels的好处是,只需要更少的线程来处理通道。事实上,可以只用一个线程处理所有的通道。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源(如内存)。因此,使用的线程越少越好。

但是,需要记住,现代的操作系统和CPU在多任务方面表现的越来越好,所以多线程的开销随着时间的推移,变得越来越小了。实际上,如果一个CPU有多个内核,不使用多任务可能是在浪费CPU能力。不管怎么说,关于那种设计的讨论应该放在另一篇不同的文章中。在这里,只要知道使用Selector能够处理多个通道就足够了。

要点

使用Selector可以构建一个非阻塞的网络服务。

在新IO实现网络程序需要依靠ServerSocketChannel类与SocketChannel

Selector实例

下面使用Selector完成一个简单的服务器的操作,服务器可以同时在多个端口进行监听,此服务器的主要功能是返回当前时间。

importjava.net.InetSocketAddress ;importjava.net.ServerSocket ;importjava.util.Set ;importjava.util.Iterator ;importjava.util.Date ;importjava.nio.channels.ServerSocketChannel ;importjava.nio.ByteBuffer ;importjava.nio.channels.SocketChannel ;importjava.nio.channels.Selector ;importjava.nio.channels.SelectionKey ;public classDateServer{public static void main(String args[]) throwsException {int ports[] = {8000,8001,8002,8003,8005,8006} ; //表示五个监听端口

Selector selector = Selector.open() ; //通过open()方法找到Selector

for(int i=0;i

ServerSocketChannel initSer= null;

initSer= ServerSocketChannel.open() ; //打开服务器的通道

initSer.configureBlocking(false) ; //服务器配置为非阻塞

ServerSocket initSock =initSer.socket() ;

InetSocketAddress address= null;

address= new InetSocketAddress(ports[i]) ; //实例化绑定地址

initSock.bind(address) ; //进行服务的绑定

initSer.register(selector,SelectionKey.OP_ACCEPT) ; //等待连接

System.out.println("服务器运行,在" + ports[i] + "端口监听。") ;

}//要接收全部生成的key,并通过连接进行判断是否获取客户端的输出

int keysAdd = 0;while((keysAdd=selector.select())>0){ //选择一组键,并且相应的通道已经准备就绪

Set selectedKeys = selector.selectedKeys() ;//取出全部生成的key

Iterator iter =selectedKeys.iterator() ;while(iter.hasNext()){

SelectionKey key= iter.next() ; //取出每一个key

if(key.isAcceptable()){

ServerSocketChannel server=(ServerSocketChannel)key.channel() ;

SocketChannel client= server.accept() ; //接收新连接

client.configureBlocking(false) ;//配置为非阻塞

ByteBuffer outBuf = ByteBuffer.allocateDirect(1024) ; // outBuf.put(("当前的时间为:" + new Date()).getBytes()) ; //向缓冲区中设置内容

outBuf.flip() ;

client.write(outBuf) ;//输出内容

client.close() ; //关闭

}

}

selectedKeys.clear() ;//清楚全部的key

}

}

}

服务器完成之后可以使用Telnet命令完成,这样就完成了一个一部的操作服务器。

xnio java_java基础篇---新I/O技术(NIO)相关推荐

  1. 【linux】循序渐进学运维-基础篇-磁盘加密解密技术

    大家好,我是高胜寒,本文是Linux运维-循序渐进学运维-基础篇的第57篇文章. 文章目录 前言: 实验步骤 1. 对磁盘进行分区格式化 2. 对新建的分区进行加密 3. 挂载测试 a) 加密情况下无 ...

  2. Java基础篇:封装、继承、多态三大特性

    目录: 一.Java三大特性之:封装 二.Java三大特性之:继承 三.Java三大特性之:多态 一.Java三大特性之:封装 1.什么是封装: 封装,就是将数据和基于数据的操作封装在一起,数据被保护 ...

  3. 视频教程-C# For Unity系列之基础篇-Unity3D

    C# For Unity系列之基础篇 二十多年的软件开发与教学经验IT技术布道者,资深软件工程师.具备深厚编程语言经验,在国内上市企业做项目经理.研发经理,熟悉企业大型软件运作管理过程.软件架构设计理 ...

  4. java基础篇_java基础篇1

    JAVA基础篇1 注释 单行注释 //这是一个单行注释,由两个斜杠组成,不能嵌套多行注释 多行注释 /*这是一个 多行注释 ,//里面不能嵌套多行注释, 但是可以嵌套单行注释*/ 文档注释 /**ja ...

  5. Linux技术研究-基础篇(raid与LVM,配额)

    Linux技术研究-基础篇(raid与LVM,配额) 创建RAID-5 若想建立新的md1设备 只在/dev下建立还不够 重启后会消失 固化的方法是 为了使udev自动产生/dev/md1, /dev ...

  6. 机器学习(四):剪枝技术(基础篇)

    机器学习(四):剪枝技术(基础篇) 相关的决策树文章: 机器学习(四)ID3决策树 机器学习(四)C4.5决策树 机器学习(四)CART分类树 机器学习(四)CART回归树 机器学习(四)决策树绘图 ...

  7. 生物信息学——基础篇:一至三代测序技术

    生物信息学 生物信息学--基础篇:一至三代测序技术 文章目录 生物信息学 一.一代测序 二.二代测序 三.三代测序 四.总结 一.一代测序 概述:一代测序(又称Sanger测序). 原理:Sanger ...

  8. Linux技术研究-基础篇(启动和自动挂载)

    Linux技术研究-基础篇(启动和自动挂载) 系统启动流程 如果有一天你的服务器启动不了,面对屏幕上的各种各样的提示素手无策. 你不知道服务器出了什么问题,无法判断启动到了哪个环节. 若想排查出问题原 ...

  9. Spring+SpringMVC+MyBatis+easyUI整合基础篇(一)项目简述及技术选型介绍

    作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 萌芽阶段 很久之前就开始打算整理一下自己的技术博客了,由于各种原因( ...

最新文章

  1. Javascript:DOM动态创建元素实例应用
  2. php 单用户登录,Linux 系统的单用户模式、修复模式、跨控制台登录在系统修复中的运用...
  3. python跨包导入包_python引入跨模块包
  4. [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
  5. Javascript 构造函数模式、原型模式
  6. Win10电脑如何批量修改文件名
  7. Python-Matplotlib可视化(4)——添加注释让统计图通俗易懂
  8. matlab 计算图像的基本参数
  9. 计算机考证包括cad吗
  10. 微信 app---uwp
  11. lua——牛牛牌型处理相关算法(上)——牌值数据
  12. webp的js插件_网页及CSS使用JS脚本加载webP图片
  13. Linux系统用户添加到用户组
  14. Linux Ubuntu16.04 Python3.5.2 Cuda10.1 TITAN XP安装fastai v1
  15. 推荐几个2020年最实用的网站!
  16. 第5 部分 EIGRP
  17. linux命令之 whatis
  18. spring学习-4-事务
  19. 贪吃蛇大作战ai_二 贪吃蛇大作战!
  20. 题目42:一笔画问题

热门文章

  1. 2020倩女幽魂服务器正在维修,倩女幽魂手游2020年12月3日维护公告
  2. 修改对象的某个属性的值_什么是类,什么是对象
  3. Codeforces 1093D Beautiful Graph
  4. leetcode 滴滴_一个菜逼程序媛的求职历程(秋招已拿阿里、网易、滴滴等校招offer)...
  5. oracle管理认证方式,关于Oracle数据库管理员认证方法简述
  6. 锁定计算机.exe,一键锁定计算机的方法
  7. hadoop的idea连接配置_idea远程连接hadoop(macOS)
  8. 深度学习(22)神经网络与全连接层五: 误差计算
  9. 原生js绑定click为什么点一次执行两次_前端小知识10点(2020.10.8)
  10. makefile如何减小可执行文件的大小(没有用到的函数不参与链接)