NIO官网叫New IO 也可以叫做式非阻塞式IO NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同,NIO支持面向缓冲区,基于通道的IO操作,NIO将以更高效的方式进行文件的读写操作
原来的IO是面对数据流 传统的IO是单向的 阻塞式的IO
而NIO面向缓冲区(通道)(铁路) 通道只负责运输 数据只在缓冲区 非阻塞的IO 拥有选择器
NIO简而言之:通道负责传输,,缓冲区负责存储
除了Boolean之外 每个基本的数据类型都有缓冲区
ByteBuffer常用的
上述缓冲区的管理方式都是一致的 通过allocate()获取缓冲区
ByteBuffer bb = ByteBuffer.allocate(1024);
存数据的和取方法
put();
get();
flip():切换读或写方法莫模式flip 换切换以下3个属性的位置!!!
rewind():重复读取数据
clear清空缓冲区回到了最初的状态 里面的数据还在 只是移动角标位置
通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中
数据没办法直接传输 要从磁盘写道内核地址空间 再写到用户地址空间
通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率
Zero copy
/**
* 1.通道(channel):用于原节点与目标节点的连接,在javaNIO中负责缓冲区中数据传输
* channel本身不存储数据 需要配合缓冲区进行传输
* 2.通道的主要实现类
* java.nio.channels.channel
* ---FileChannel 用于本地传输
* ---SocketChaneel TCP
* ---ServerSocketChannel
* ---DatagramChannel UDP
* 3。Java支持通道提供了getChannel()方法
* 本地IO
* ---FileInputStream/FileOutputStream
* ---RandomAccessFile
* 网络IO
* Socket
* ServerSocket
* DatagramSocket
* jdk7中的nio2 在JDK7以后的nio统称NIO2
* 提供了一个静态方法open() 也可以获取通道
* 针对Files工具类的newByteChannel()
* 4.通道之间的数据传输
* transferFrom();
* transTo();
*/
public class NIOTest {
@Test
public void test() throws Exception {
//一,利用通道完成文件的复制(非直接缓冲区)
FileInputStream fis = new FileInputStream("jvm.png");
FileOutputStream fos = new FileOutputStream("1.png");
//1.获取通道
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
//2.分配一个指定大小的缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//3.将通道中的数据存入缓冲区中
while(inChannel.read(buf) != -1){
//4.将缓冲区中的数据再写入通道
buf.flip(); // 切换成读数据的模式
outChannel.write(buf);
buf.clear(); //清空缓冲区
}
outChannel.close();
inChannel.close();
fos.close();
fis.close();
}
@Test
public void test2() throws IOException {
//使用直接缓冲区完成复制文件
FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
//CREAT_NEW 如果有报错 没有创建
FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
//内存映射文件 直接缓冲区只有bytebuffer支持
MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMapperBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//不需要通道 直接操作缓冲区
byte[] dst = new byte[inMappedBuf.limit()];
inMappedBuf.get(dst);
outMapperBuf.put(dst);
inChannel.close();
outChannel.close();
}
@Test
public void test3() throws Exception {
//直接缓冲区的方式
FileChannel inChannel = FileChannel.open(Paths.get("1.png"), StandardOpenOption.READ);
//CREAT_NEW 如果有报错 没有创建
FileChannel outChannel = FileChannel.open(Paths.get("3.png"), StandardOpenOption.WRITE,StandardOpenOption.READ,StandardOpenOption.CREATE_NEW);
long l = inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
}
}
分散读取 将通道的数据分散到多个缓冲区中
聚集写入 将多个缓冲区的数据聚集到一个通道中
NIO与IO的区别 IO是阻塞式的 如果客户端发送一个读写请求 服务端如果不能够确定发送的东西是否有效 是否有数据就会发生阻塞 判断内核地址空间有没有数据
NIO式非阻塞 式相较于网络通信来说的
就是在文件中间加一个选择器 就是在准备好了的时候才通过选择器建立连接,,而不会因为服务端的不确定而出现了阻塞
//服务器端
public static void main(String[] args) throws IOException {
//1.获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
//2.切换非阻塞模式
ssChannel.configureBlocking(false);
//3.绑定连接
ssChannel.bind(new InetSocketAddress(10086));
//4.获取选择器
Selector selector = Selector.open();
//5.将通道注册到选择器上 后面的参数是选择键 监控状态的什么时间/状态 读写接收
//ACCEPT接收 指定监听事件
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
//6.轮询式的获取选择器上已经准备就绪的事件
while (selector.select() > 0) {
Set<SelectionKey> selectionKeys = selector.selectedKeys();
//7.获取当前选择器中所有注册的选择键(已就绪的监听事件)
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
//8.获取准备就绪的事件
SelectionKey sk = iterator.next();
//9.判断具体是什么事件准备就绪
if(sk.isAcceptable()){
//10.若接收就绪 获取客户端连接
SocketChannel sChannel = ssChannel.accept();
//11.把通道切换成非阻塞模式
sChannel.configureBlocking(false);
//12.将该通道注册到选择器上
sChannel.register(selector,SelectionKey.OP_READ);
}else if(sk.isReadable()){
//13.获取当前选择器上“读就绪”状态的通道
SocketChannel sChannel = (SocketChannel) sk.channel();
//14.读取数据
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = 0;
while((len = sChannel.read(buf))>0){
buf.flip();
System.out.println(new String(buf.array(),0,len));
buf.clear();
}
}
//15.取消选择键 SelectorKey
iterator.remove();
}
}
}
//客户端
public static void main(String[] args) throws IOException {
//1.获取通道
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 10086));
//2.切换成非阻塞模式
sChannel.configureBlocking(false);
//3.分配缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
//4.发送数据到缓冲区
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
String str = scanner.next();
buf.put((new Date().toString()+"\n"+str).getBytes());
buf.flip();
sChannel.write(buf);
buf.clear();
}
//5.关闭通道
sChannel.close();
}