写在前面
Java NIO(New IO) 是从JDK1.4版本开始引入的一个新的IO API,可以替代标准的Java IO API,NIO与原来的IO有相同的作用和目的,但是使用的方法完全不同,NIO支持面向缓冲区,基于通道的IO操作,NIO将以更高的方式进行文件的读写操作。
1.传统IO与NIO的区别
image.png1.1传统IO
传统IO面向流,当程序与文件建立链接之后,通过操作字节数组来进行读写(read,write)字节流,
image.png1.2 NIO
NIO面向缓冲区,基于通道进行数据传输,当文件与程序建立通道之后,数据存储在缓冲区中,进行运输,缓冲区是双向的,可以来回走,通道就好比火车道,缓冲区就好比火车,程序和文件相当于两个车站,挡在某个车站接了人,运到另一个车站,还可以接着接人,在回来
image.png2.NIO入门
NIO系统核心在于:通道(Channel)和缓冲区(Buffer),选择器(Selector),通道表示打开到IO设备(文件,套接字(Socket))的链接,若需要使用NIO系统,需要获取用于链接Io设备的通道以及容纳数据的缓冲区,然后操作缓冲区,对数据进行处理
2.1 缓冲区(Buffer)
2.1.1 常用数据类型的缓冲区
缓冲区负责数据的存取,底层使用数组实现的,用于存储不同类型的数据
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
2.1.2 缓冲区的方法
put():存放数据
get():获取数据
wrap(char[] arras):用自己的数组用作缓冲区的备份存储器
2.1.3 核心属性
所有的缓冲区都继承Buffer类
image.png
private int mark = -1; 标记当前操作数据的位置,使用reset方法可以返回这个位置
private int position = 0; 表示当前操作数据的位置
private int limit; 界限,表示缓冲区中可以操作数据的量(limit后面的数据不可以操作)
private int capacity;表示缓冲区的容量,一旦确定不能改变
通过实例看一下:
image.png代码:
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("----put()方法");
byteBuffer.put("abcde".getBytes());
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("----flip()方法");
byteBuffer.flip();
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("----get()方法");
byte[] dst = new byte[byteBuffer.limit()];
byteBuffer.get(dst);
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("---rewind()方法,重读");
byteBuffer.rewind();
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("----第二次get()方法");
byte[] dst1 = new byte[byteBuffer.limit()];
byteBuffer.get(dst1);
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
System.out.println("-----clear方法,清空缓冲区");
byteBuffer.clear();
System.out.println(byteBuffer.position());
System.out.println(byteBuffer.limit());
System.out.println(byteBuffer.capacity());
效果:
image.png
2.1.4 获取缓冲区的方法
四、直接缓冲区与非直接缓冲区
非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM内存中
直接缓冲区:通过allocateDirect()方法分配缓冲区,缓冲区建立在操作系统的物理内存中
操作:
ByteBuffer byteBuffer = ByteBuffer.allocate(10);
byteBuffer.put("abcdefg".getBytes());
byteBuffer.flip();
byte[] dst = new byte[byteBuffer.limit()];
byteBuffer.get(dst,0,2);
System.out.println(new String(dst,0,2));
System.out.println(byteBuffer.position());
byteBuffer.mark();//标记一下当前的position的位置
byteBuffer.get(dst,2,2);
System.out.println(new String(dst,2,2));
System.out.println(byteBuffer.position());
byteBuffer.reset();//恢复mark的位置
System.out.println(byteBuffer.position());
效果:
image.png
mark之后,调用reset方法,position会回到mark的位置,重新读
2.2 通道
通道用于源节点与目标节点的连接,在JavaNIO中负责缓冲区中的数据的传输
2.2.1通道的主要实现类
image.png2.2.2 获取通道的办法
image.png
使用getChannel方法
@Test
public void test1() {
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
FileChannel inChannel = null;
FileChannel outChannel = null;
try {
inputStream = new FileInputStream("1.txt");
outputStream = new FileOutputStream("2.txt");
//1.获取通道
inChannel = inputStream.getChannel();
outChannel = outputStream.getChannel();
//2.分配缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//3.将通道中的数据写入缓冲区,将缓冲区的数据读出来写入通道
while (inChannel.read(byteBuffer) != -1) {
//将缓冲区的数据写入通道
byteBuffer.flip();
outChannel.write(byteBuffer);
byteBuffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inChannel != null) {
try {
inChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outChannel != null) {
try {
outChannel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用open方法
@Test
public void test2() throws IOException {
//得到通道
FileChannel inChannel = FileChannel.open(Paths.get("1.txt"), StandardOpenOption.READ);
FileChannel outChannel = FileChannel.open(Paths.get("3.txt"), StandardOpenOption.WRITE,
StandardOpenOption.READ, StandardOpenOption.CREATE);
//2.创建内存映射文件
MappedByteBuffer inMapper = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
MappedByteBuffer outMapper = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
//直接对缓冲区中的数据进行操作
byte[] dst = new byte[inMapper.limit()];
inMapper.get(dst);
outMapper.put(dst);
inChannel.close();
outChannel.close();
}
2.3 阻塞与非阻塞
观看下一篇https://www.jianshu.com/p/dbe9b22d695e
QQ群:552113611
网友评论