java-NIO 学习(chapter1)
发现写的有点乱,大家各取所需 - - !
一,nio 是New I/O 的简称,在jdk1.4版本后开始提供,位于java.nio.*包中。其目的就是为了提高文件和网络I/O的速度,如果你在代码中使用了老I/O的FileInputStream,FileOutputStream,RandomAccessFile三个类时,你不用去纠结要不要用NIO去替换他们,因为这三类已经用NIO重新写过了。
二,java NIO由缓冲区(Buffer)、通道(Channel)、选择器(Selector)核心组成,用《Tinking in Java》中的话来解释他们的关系:想象有一个煤矿,通道是包含煤矿的矿藏,而缓冲器则是派送到矿藏的卡车,卡车满载煤矿而归,我们再从卡车上获得煤矿,我们并没有和通道进行交互,我们只和缓冲器交互,把缓冲器派送到通道,通道要么从缓冲器获得数据,要么向缓冲器发送数据。不过作者并没有解释Selector在其中的定义,稍后我会在学习后加以补充。
三,首先来看下Channel ,看下官方文档的定义:
A channel represents an open connection to an entity such as a hardware device, a file, a network socket, or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.
//通道表示连到一个实体(例如:硬件设备、文件、网络套接字或者能执行一个或多个不同 I/O 操作(例如:读或写)的程序组件)的开放连接。(感觉和没说一样。。。。)
先看个channel 的简单实例吧,中间有用到buffer,会在后面详解。
public class Main {
public static final int BUFFER_SIZE = 4;
public static void main(String[] args) throws Exception {
// test channel
File file = new File("C:\\Users\\Administrator\\Desktop\\testOut.txt");
FileInputStream inputStream = new FileInputStream(file);
FileChannel channel = inputStream.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); //创建缓冲区
int size = 0;
while ((size =channel.read(buffer)) != -1) {
// System.out.println(size);
buffer.flip(); //这个会在后面详解,反正现在记住,写模式切换到读模式时,要调用flip()方法
while (buffer.hasRemaining()){
System.out.println((char)buffer.get());
}
buffer.clear();//读模式切换到写模式,清空buffer
}
channel.close();
inputStream.close();
}
}
上面的代码我们用到了FileChannel,实际上在JDK中Channel只是一个interface, 实现了Channel接口的类有:
其中最重要的几个类:
- DatagramChannel 能通过UDP读写网络中的数据
- FileChannel 从文件中读写数据
- SocketChannel 能通过TCP读写网络中的数据。
- ServerSocketChannel 可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
从上面的代码中,发现channel 有点类似Stream,但其实还是有很多的不同之处:
- channel既可以读数据,也可以写数据。Stream的读写则是单向的
- channel可以异步的读写
- channel 总是要和buffer交互,要么从buffer中读数据,要么从buffer中写数据
我们可以异步地关闭和中断 NIO 通道。所以,如果一个线程在某条通道的 I/O 操作上阻塞时,那么另一个线程可以将这条通道关闭。类似地,如果一个线程在某条通道的 I/O 操作上阻塞时,那么另一个线程可以中断这个阻塞线程。
四,Buffer,从上面的例子和章节中,我们可以知道,buffer 主要用来和Channel 进行交互,数据可以从Channel 读入到buffer中,也可以从buffer 写入 channel。
buffer 本质上其实就是一块可以进行读写的内存(Heap),只是被包装成Buffer对象,并提供了一组方法,用来进行对改内存的访问。
从上面channel的代码中发现,buffer的使用一般分为5个步骤:
- 1.创建:调用自身的静态工厂方法创建buffer
- 2.读取数据到buffer: 调用channel的read()方法
- 3.切换模式,调用自身的flip()方法
- 4.从buffer中读取数据
- 5.清空buffer。(从某种意义上说并不是清空)调用 clear()和compact()方法(后面解释这两者的区别)
234