NIO详解
NIO
前言
NIO即New IO,这个库是在JDK1.4中才引入的。NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多。在Java API中提供了两套NIO,一套是针对标准输入输出NIO,另一套就是网络编程NIO。
IO与NIO的区别
- IO流是面向流的,属于阻塞IO,没有选择器。
- NIO流是面向块(缓冲区),属于非阻塞IO有选择器。
其中最大的区别就是一个面向流,一个面向缓冲区。- 面向流:IO流每次读取一个字节或者多个,直到读完为止。不能对流中的数据进行操作。
- 面向缓冲区:NIO流是将数据放到一个缓冲区,需要时可以对缓冲区中的数据进行操作,这样就可以更加灵活的操作数据了。(就好像IO流是一根水管,而NIO是一个运水车)
Buffer(缓冲区)
Buffer
是一个抽象类;
子类有:ByteBuffer
,CharBuffer
,DoubleBuffer
,FloatBuffer
,IntBuffer
,LongBuffer
,ShortBuffer
核心类(常用类):ByteBuffer
和CharBuffer
其中ByteBuffer
有一个子类MappedByteBuffer
(MappedByteBuffer
类能够将文件直接映射到内存中,那么这样我们就可以像访问内存一样访问文件,非常方便)
创建Buffer
因为Buffer都是抽象类,无法直接实例化。创建缓冲区要调用XxxBuffer allocate(int capacity),XxxBuffer allocateDirect(int capacity),参数是缓冲区容量。
eg:获取ByteBuffer
static ByteBuffer allocate(int capacity)
分配一个新的字节缓冲区(普通Buffer)
static ByteBuffer allocateDirect(int capacity)
分配新的直接字节缓冲区(直接Buffer)
二者的区别:
- 创建普通Buffer成本低,读写的效率不高
- 因为创建直接Buffer成本高,所以我们一般用在Buffer生存周期较长的时候使用
- 只有ByteBuffer才能够创建直接Buffer,其他的Buffer对象是不能够创建
- 如果创建了直接Buffer但是我又想要使用其他Buffer的功能,可以将ByteBuffer转换成其他Buffer
Buffer参数
- capacity(容量):缓冲区的容量,不可以为负数,一旦创建了就不能够改变
- limit(界限):是缓冲区读写数据的终止点,limit之后的区域无法访问
- position(起始指针):是缓冲区读写数据的起始点,初始值为0。position随着数据的加入而改变,例如读取2个数据到Buffer中,则position = 2
- mark(标记):该索引能够用于下次读取或者写入,mark在0~position之间,设置该值就会把position移动到mark处
Buffer方法
- flip():读取模式;确定缓冲区数据的起始点和终止点,为输出数据做准备(即写入通道), 将limit的值改为postion的值,同时将postion归0
- 特点: 就是为下一次数据的读取做好准备
- clear():写入模式;缓冲区初始化,准备再次接收新数据到缓冲区,将limit改为capacity的值,同时将postion归0
- 特点: 就是为下一次数据的写入做好准备
- get()和put():获取元素和存放元素。使用clear()之后,无法直接使用get()获取元素,需要使用get(int index)根据索引值来获取相应元素
- hasRemaining():判断postion到limit之间是否还有元素。
public static void main(String[] args) {
CharBuffer buffer = CharBuffer.allocate(8);
// Buffer已经准备好了向Buffer中写数据 写模式
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 0
buffer.put('a');
buffer.put('b');
buffer.put('c');
System.out.println("------------------------");
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 3
System.out.println("------------------------");
// 切换模式 ,limit变为position的位置然后将position变为0
buffer.flip();
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 3
System.out.println("position:" + buffer.position()); // 0
System.out.println("------------------------");
System.out.println("------------------");
buffer.clear(); // 将postion 清 0 ,将limit = capacity
System.out.println("capacity:" + buffer.capacity()); // 8
System.out.println("limit:" + buffer.limit()); // 8
System.out.println("position:" + buffer.position()); // 0
// 注意: 调用clear方法只是将读模式改为写模式,并不会清空缓冲区的数据
}
Channel(通道)
Channel原理类似于传统的流对象,区别在于:
1.Channel能够将指定的部分或者全部文件映射到内存中
2.程序如果想要读取Channel中的数据,不能够直接读写,必须经过Buffer
简单来说:Channel通过Buffer(缓冲区)进行读写操作。read()表示读取通道数据到缓冲区,write()表示把缓冲区数据写入到通道。
Channel实现类
- FileChannel 和文件相关的通道
- DatagramChannel 和UDP协议传输数据相关的通道
- SocketChannel 和TCP协议相关的数据传输通道
- ServerSocket 和TCP协议相关的数据传输通道
- Pipe.SinkChannel、Pipe.SourceChannel //线程通信管道传输数据
Channel常用方法
- read() : 将Channel中的数据读取到Buffer中
- write() : 向Buffer中写入数据
- map(): 将channel中的数据全部或者部分映射到Buffer中(MappedByteBuffer,本质也是一个ByteBuffer),map()方法参数(读写模式,映射起始位置,数据长度)。
inChannel.map(mode, position, size)
MappedByteBuffer mappBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
public static void main(String[] args) throws IOException {
File srcFile = new File("nio-a.txt");
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(new File("nio-b.txt"));
// 获取Channel对象
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
// 获取MapByteBuffer对象
MappedByteBuffer mapBuffer = inChannel.map(MapMode.READ_ONLY, 0, srcFile.length());
//字符集解码器
Charset charset = Charset.forName("GBK");
outChannel.write(mapBuffer);
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(mapBuffer);
System.out.println(charBuffer);
}
通道可以异步读写,异步读写表示通道执行读写操作时,也能做别的事情,解决线程阻塞。如果使用文件管道(FileChannel),建议用RandomAccessFile来创建管道,因为该类支持读写模式以及有大量处理文件的方法。
public static void main(String[] args) throws Exception {
File f = new File("nio-a.txt");
RandomAccessFile raf = new RandomAccessFile(f, "rw");
FileChannel channel = raf.getChannel();
MappedByteBuffer mapBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, f.length());
// raf.seek(f.length());
channel.position(f.length());
channel.write(mapBuffer);
}
Charset(字符集)
理解为现实生活的编码表对象
当使用NIO来获取文件内容时,如果是文本数据,那么需要进行转码,才能查看正确内容,这就需要解码器。 如果要把字符数据写入文件,需要将CharBuffer转码成ByteBuffer,这就需要编码器。
- 包含了字节和 Unicode 字符之间转换的 charset,还定义了用于创建解码器和编码器以及获取与 charset 关联的各种方法
- CharsetDecoder(解码器):把字节转成字符,例如查看文本数据,需要转成字符才能查看,如果是字节,就看不懂了。
- CharsetEncoder(编码器):把字符转成字节,才能被计算机理解。 因为字节是计算机最小的存储单位,所以Channel的IO操作都与ByteBuffer有关
- 解码器和编码器都不能直接创建,需要一个Charset对象来创建对应的解码器和编码器。
Charset常用方法
- forName():根据传入的字符集获得对应的字符集对象。
- defaultCharset():获得当前使用的默认字符集。
- availableCharsets():获得所有有效的字符集。
NIO遍历文件
public static void main(String[] args) throws IOException {
//匿名子对象实现FileVisitor接口
FileVisitor<Path> visitor = new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
System.out.println("正在访问" + path + "文件");
if(path.endsWith("NIODemo.java")){
System.out.println("恭喜您找到Java");
return FileVisitResult.CONTINUE;
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) throws IOException {
System.out.println("准备访问" + path + "文件");
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path path, IOException exc) throws IOException {
System.out.println("准备访问" + path + "文件失败");
System.out.println(exc.getMessage());
return FileVisitResult.CONTINUE;
}
};
//访问文件树
Files.walkFileTree(Paths.get("D:\\JavaSE"), visitor);
}
以上
@Fzxey
NIO详解的更多相关文章
- Java NIO 详解(一)
一.基本概念描述 1.1 I/O简介 I/O即输入输出,是计算机与外界世界的一个借口.IO操作的实际主题是操作系统.在java编程中,一般使用流的方式来处理IO,所有的IO都被视作是单个字节的移动,通 ...
- Java网络编程和NIO详解开篇:Java网络编程基础
Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...
- Java网络编程和NIO详解8:浅析mmap和Direct Buffer
Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...
- Java网络编程和NIO详解9:基于NIO的网络编程框架Netty
Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...
- Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...
- Java网络编程和NIO详解6:Linux epoll实现原理详解
Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...
- Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO
Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...
- Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector
Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...
- Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型
Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...
- Java网络编程和NIO详解3:IO模型与Java网络编程模型
Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...
随机推荐
- MQTT--Paho C Client 的实现和详解
概述 在文章Paho - MQTT C Cient的实现中,我介绍了如何使用Paho开源项目创建MQTTClient_pulish客户端.但只是简单的介绍了使用方法,而且客户端的结果与之前介绍的并不 ...
- ubuntu搭建web服务器
https://www.linuxidc.com/Linux/2015-11/125477.htm 到“sudo apt-get install libapache2-mod-php5”出现1错误.
- 卡常的编译命令(含O2优化)
不解释,直接来 //包括O2,O3之类的编译命令 //直接copy and paste #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma ...
- AES学习小结
AES是基于数据块的加密方式,即每次处理的数据是一块(16字节),当数据不是16字节的倍数时填充,这就是所谓的分组密码(区别于基于比特位的流密码),16字节是分组长度. AES支持五种模式:CBC,C ...
- 【PXC】关于限流的参数,状态值说明
一.什么是流控(FC)?如何工作? 节点接收写集并把它们按照全局顺序组织起来,节点将接收到的未应用和提交的事务保存在接收队列中,当这个接收队列达到一定的大小,将触发限流:此时节点将暂停复制,节点会先处 ...
- JavaWeb中的高级知识总结
知识结构图 文件下载 默认情况下,如果浏览器可以处理Content-Type响应头中指定数据类型,浏览器就会直接处理,比如显示出HTML页面(text/html),或者显示出照片(image/png) ...
- Maven--仓库的分类
对于 Maven 仓库来说,仓库只分为两类:本地仓库和远程仓库. 当 Maven 根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用:如果本地仓库不存在此构件,或者需要查 ...
- 国产手机早就异军突起,为何还是有很多人“迷恋”iPhone?
近几年,国产手机不论是从外观上还是设计上,以及销量上都比前有了长足的进步,手机的品质和售后也在不断提升.这也让中国手机厂商不断的推出了拥有自己品牌特色的产品.特别是2018年不少国产手机品牌的旗舰级产 ...
- doc文件转txt
doc文件转txt # -*- coding:utf-8 -*- # 安装pywin32包 http://sourceforge.net/projects/pywin32/files/pywin32/ ...
- 新服务器搭建-总结: 下载nginx,jdk8,docker-compose编排(安装mysql,redis) 附安装
三明SEO: 前言 如题, 公司新买了一条4核16G的服务器, 不得不重新搭建环境, 只能一一重来, 做个记录 1.nginx : 手动安装 2.jdk8: 手动安装 3. 安装docker 及doc ...