1、Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始)
2、Java NIO提供了与标准IO不同的IO工作方式。
3、nio 主要面向于网络编程
1、IO基于字节流和字符流进行操作的
2、NIO是基于通道(Channel)和缓冲区(Buffer)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
3、NIO引入了选择器的概念,选择器用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。
io 流实现过程
数据传递是单向的,写数据只管把数据往文件丢,读也是同理
并且 io 基本都是非直接缓冲区传递(速度慢)
nio 实现过程
先把数据放到缓冲区,在根据缓冲区的大小来回读取,直到数据传递完成
在这里插入图片描述
------在老的IO包中,serverSocket和socket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。
------而NIO包中的serverSocket和socket就不是这样,只要注册到一个selector中,当有数据放入通道的时候,selector就会得知哪些channel就绪,这时就可以做响应的处理,这样服务端只有一个线程就可以处理大部分情况(当然有些持续性操作,比如上传下载一个大文件,用NIO的方式不会比IO好)。
1、非直接缓冲区是直接通过拷贝的形式传递的,如从磁盘读取文件到物流空间,然后拷贝到jvm,在读取数据
优点:安全
缺点:速度慢,不是一般的慢, 直接缓冲区比非直接缓冲区大约快5倍
2、直接缓冲区是通过物流内存映射文件直接传递的
优点:速度快
缺点:不安全,占CPU(传递特别大的文件,如几个G的,特别占cpu,严重情况可能会导致电脑直接卡死)
1、直接缓冲区
2、非直接缓冲区
把1.pm4 拷贝到 2.mp4
package com.itmayiedu;
import org.junit.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
@SuppressWarnings("ALL")
public class Test003 {
/**
* 直接缓冲区
* @throws IOException
*/
@Test
public void test002() throws IOException {
long statTime=System.currentTimeMillis();
//创建管道
FileChannel inChannel= FileChannel.open(Paths.get("f://1.mp4"), StandardOpenOption.READ);
FileChannel outChannel=FileChannel.open(Paths.get("f://2.mp4"), StandardOpenOption.READ,StandardOpenOption.WRITE, StandardOpenOption.CREATE);
//定义映射文件
MappedByteBuffer inMappedByte = inChannel.map(MapMode.READ_ONLY,0, inChannel.size());
MappedByteBuffer outMappedByte = outChannel.map(MapMode.READ_WRITE,0, inChannel.size());
//直接对缓冲区操作
byte[] dsf=new byte[inMappedByte.limit()];
inMappedByte.get(dsf);
outMappedByte.put(dsf);
inChannel.close();
outChannel.close();
long endTime=System.currentTimeMillis();
System.out.println("操作直接缓冲区耗时时间:"+(endTime-statTime));
}
/**
* 非直接缓冲区 读写操作
* @throws IOException
*/
@Test
public void test001() throws IOException {
long statTime=System.currentTimeMillis();
// 读入流
FileInputStream fst = new FileInputStream("f://1.mp4");
// 写入流
FileOutputStream fos = new FileOutputStream("f://2.mp4");
// 创建通道
FileChannel inChannel = fst.getChannel();
FileChannel outChannel = fos.getChannel();
// 分配指定大小缓冲区
ByteBuffer buf = ByteBuffer.allocate(1024);
while (inChannel.read(buf) != -1) {
// 开启读取模式
buf.flip();
// 将数据写入到通道中
outChannel.write(buf);
buf.clear();
}
// 关闭通道 、关闭连接
inChannel.close();
outChannel.close();
fos.close();
fst.close();
long endTime=System.currentTimeMillis();
System.out.println("操作非直接缓冲区耗时时间:"+(endTime-statTime));
}
}
首先先介绍一下RandomAccessFile || RandomAccessFile
//创建随机存储文件流,文件属性由参数File对象指定
RandomAccessFile(File file , String mode)
//创建随机存储文件流,文件名由参数name指定
RandomAccessFile(String name , String mode)
这两个构造方法均涉及到一个String类型的参数mode,它决定随机存储文件流的操作模式,其中mode值及对应的含义如下:
“r”: 以只读的方式打开,调用该对象的任何write(写)方法都会导致IOException异常
“rw”: 以读、写方式打开,支持文件的读取或写入。若文件不存在,则创建之。
“rws”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。这里的“s”表示synchronous(同步)的意思
“rwd”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。使用“rwd”模式仅要求将文件的内容更新到存储设备中,而使用“rws”模式除了更新文件的内容,还要更新文件的元数据(metadata),因此至少要求1次低级别的I/O操作
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
@SuppressWarnings("ALL")
public class Test004 {
public static void main(String[] args) throws IOException {
try {
//分散读取
RandomAccessFile randomAccessFile = new RandomAccessFile("f://1.txt","rw");
//获取channel
FileChannel fileChannel = randomAccessFile.getChannel();
//分散读取,就是使用多个buffer来装数据,可继续增加,值为名称缓冲区大小
ByteBuffer by1 = ByteBuffer.allocate(20);
ByteBuffer by2 = ByteBuffer.allocate(50);
ByteBuffer[] byteBuffers = {by1,by2};
//分散聚合
RandomAccessFile randomAccessFile1 = new RandomAccessFile("f://2.txt","rw");
FileChannel fileChannel1 = randomAccessFile1.getChannel();
while (fileChannel.read(byteBuffers) != -1){
by1.flip();
by2.flip();
System.out.println("------------------打印数据by1-------------------");
System.out.println(new String(byteBuffers[0].array(), 0, byteBuffers[0].limit(),"utf-8"));
System.out.println("------------------打印数据by2-------------------");
System.out.println(new String(byteBuffers[1].array(), 0, byteBuffers[1].limit(),"utf-8"));
//聚合,同上
fileChannel1.write(byteBuffers);
by1.clear();
by2.clear();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}