Java NIO (New IO,Non-Blocking IO)是从Java 1.4版本开始引入的一套新的IO API,可以替代标准的Java IO API。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区的、基于通道的IO操作。NIO将以更加高效的方式进行文件的读写操作。Non-Blocking应该是最好的理解
随着 JDK 7 的发布,Java对NIO进行了极大的扩展,增强了对文件处理和文件系统特性的支持,以至于我们称他们为 NIO.2。因为 NIO 提供的一些功能,NIO已经成为文件处理中越来越重要的部分。
IO: 面向流 单向的 面向缓冲区:通道可以是单双向的
阻塞IO
NIO:面向缓冲区(Buffer Oriented):通道可以是单向的,也可以是双向的
非阻塞IO(Non Blocking IO)
选择器(Selectors)
NIO的核心在于:通道和缓冲区(Buffer),通道表示IO源daoIO设备(例如:文件,套接字)的连接,若需要时使用NIO需要获取IO设备中的通道以及用于容纳的数据缓冲区,对数据进行处理
缓冲区底层就是数组
简而言之:Channel 负责传输,Buffer负责存储
容量 (capacity) :表示 Buffer 最大数据容量,一旦声明后,不能更改。通过Buffer中的capacity()获取。缓冲区capacity不能为负。
限制 (limit):第一个不应该读取或写入的数据的索引,即位于 limit
后的数据不可读写。通过Buffer中的limit()获取。缓冲区的limit不能为负,并且不能大于其capacity。 位置 (position):当前要读取或写入数据的索引。通过Buffer中的position()获取。缓冲区的position不能为负,并且不能大于其limit。
标记 (mark):标记是一个索引,通过 Buffer 中的 mark() 方法将mark标记为当前position位置。
之后可以通过调用 reset() 方法将 position恢复到标记的mark处。 标记、位置、限制、容量遵守以下不变式:
0 <= mark <= position <= limit <= capacity
package com.nyist.NIO;
/** * Created with IntelliJ IDEA. * User: @子玉 [2375900377] * Date: 2018-03-30 * Time: 11:37 * Description: */
import org.junit.Test;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
/** * 一.Nio中传输中的两个重要的概念: * Buffer:缓冲区 负责数据的存储(读写) * channel :通道 代表了数据源与IO节点 (文件,网络socket) 之间的链接,负责传输Buffer * * 二。 java.nio.Buffer * |--------ByteBuffer * |--------CharBuffer * * |--------IntBuffer * |--------DoubleBuffer * |--------ShortBuffer * |--------LongBuffer * |--------DoubleBuffer 底层对应类型的数组 xxxBuffer的常用属性 capacity :容量 limit : 限制 默认的时候与capation 的值一样 position : 位置 mark : 标记 */
class BufferTest {
@Test
public void test1(){
ByteBuffer byteBuffer = ByteBuffer.allocate(10);//底层为10 的byte[]数组
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
// System.out.println(byteBuffer.mark());
byteBuffer.put("ddd".getBytes());
System.out.println("***************");
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());//每一次put都会将值移动一次
System.out.println("**********flip()********");
byteBuffer.flip();//将存入数据模式变成取出数据模式 已经存入的数据posstion又变成0,从头继续读
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println("----"+byteBuffer.position());
System.out.println("**********get()********");
System.out.println((char)byteBuffer.get()); //每get一次posstion+1
System.out.println((char)byteBuffer.get());
System.out.println(byteBuffer.capacity());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.position());
byteBuffer.rewind();//重置position
byteBuffer.clear();//清空 回到用户最初的状态 10,10,0
System.out.println((char)byteBuffer.get());
}
}
channel本身不能存数据,只能与buffer交互
主要实现类:
二、主要实现类:
* java.nio.channels.Channel:
* |—-FileChannel:适用于本地数据传输
*
* |—-SocketChannel:适用于TCP中的网络传输的客户端
* |—-ServerSocketChannel:适用于TCP中的网络传输的服务器端
* |—-DatagramChannel:适用于UDP中的网络传输
*
* |—-Pipe.SinkChannel:
* |—-Pipe.SourceChannel:
*
* 三、实例化Channel:
* 方式一: 调用getChannel()
* FileInputStream—>FileChannel
* FileOutpuStream—>FileChannel
* RandomAccessFile—>FileChannel
* ————-
* Socket—>SocketChannel
* ServerSocket—>ServerSocketChannel
* DatagramSocket—>DatagramChannel
*
* 方式二: jdk7.0以上才可以使用
* 调用XxxChannel的静态方法:open(),得到XxxChannel实例。
*
* 方式三:jdk7.0以上才可以使用
* Files.newByteBuffer(),返回一个字节通道
*
* 四、Channel特点:既可以是单向的,也可以是双向的。
* |————-ServerSocketChannel TCP 监听TCP读写网络中
* |————-DatagramChannel 适用于UDP 读写网络中的数据通道
*
非直接缓存区代码实例
/** * channleb只能与buffer交互 * * //实现文件的复制 FileChannel +ByteBuffer(非直接缓冲区) */
@Test
public void test1() throws Exception {
//1.提供相应的输入输出流
FileInputStream fis = new FileInputStream("D:\\nexus.war");
FileOutputStream fos = new FileOutputStream("D:\\nexus.war2.tar");
//创建相应的Channel 通过我们的流去创建对应的通道,然后通过通道继续读写数据
FileChannel inchannel = fis.getChannel();
FileChannel outchannel = fos.getChannel();
//3.提供缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
while ((inchannel.read(byteBuffer)) != -1) {
byteBuffer.flip();//切换为读数据的模式
//如果这里不切换的话,缓存区会满
outchannel.write(byteBuffer);
byteBuffer.clear();//清空,读完当前的缓存区然后再继续
}
fis.close();
fos.close();
inchannel.close();
outchannel.close();
}
直接缓存区代码实例:
//使用FileChannel + MappedByteBuffer(直接缓冲区)-->物理内存映射文件
@Test
public void test2() throws Exception {
long start = System.currentTimeMillis();
//1.创建Channel
// FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
// FileChannel outChannel = FileChannel.open(Paths.get("3.jpg"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE);
FileChannel inChannel = FileChannel.open(Paths.get("D:\\nexus.war"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("D:\\nexus2.war"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
//2.创建得到直接缓冲区
MappedByteBuffer inMappedBuffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMappedBuffer = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//3.数据的读写
byte[] dst = new byte[inMappedBuffer.limit()];
inMappedBuffer.get(dst);//将数据写入到dst中
outMappedBuffer.put(dst);//从dst中将数据取出
//4.关闭资源
inChannel.close();
outChannel.close();
long end = System.currentTimeMillis();
System.out.println("直接缓冲区:" + (end - start));//1573-1575
}
以上是我近期的一些整理,希望可以跟大家相互交流学习。