# JavaNIO **Repository Path**: CarlosHuang/JavaNIO ## Basic Information - **Project Name**: JavaNIO - **Description**: Java NIO - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-07-26 - **Last Updated**: 2020-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # NIO ## Java IO 与 NIO的主要区别 | IO | NIO | |-------|-------| | 面向流 | 面向缓冲区 | | 阻塞IO | 非阻塞IO | | | 选择器 | ## 通道(Channel)与缓冲区(Buffer) > Channel表示打开IO设备(如,文件、套接字)的连接。若要使用NIO,则需获取用于连接IO设备的管道以及容纳数据的缓冲区。然后操作缓冲区,对数据进行处理 ### 1、[缓冲区(Buffer)](./src/buffer/TestBuffer.java) > 在Java NIO中负责数据的存取,缓冲区就是数组用于操作不同类型的数据。不同的数据类型提供了不同的缓冲区,boolean除外。 - ByteBuffer - CharBuffer - DoubleBuffer - FloatBuffer - IntBuffer - LongBuffer - ShortBuffer #### 1、使用方法 1. 使用`allocate()`方法获取一定大小的缓冲区:`ByteBuffer buffer = ByteBuffer.allocate(1024);` 2. 使用`put()`存入数据到缓冲区:`buffer.put("hello".getBytes());` 3. 使用`flip()`切换成读取数据模式:`buffer.flip();` 4. 使用`get()`获取缓冲区内的数据:`byte[] bytes = new byte[buffer.limit()]; buffer.get(bytes);` #### 2、核心属性 - `mark`:标记, 表示记录当前position的位置,可通过reset()恢复到mark的位置 - `position`:位置,缓冲区中正在操作数据的位置 - `limit`:界限,缓冲区中可以操作数据的大小。 limit后的数据不可读写 - `capacity`:容量,表示缓冲区中最大存储数据的容量,一旦声明不可改变 #### 3、直接缓冲区与非直接缓冲区 - 非直接缓冲区:通过`allocate()`方法分配缓冲区,缓冲区将建立在JVM的内存中 - 直接缓冲区:通过`allocateDirect()`方法分配缓冲区,缓冲区将直接建立在物理内存中 ### 2、[通道](./src/channel/TestChannel.java) > Channel表示IO源与目标打开的连接,类似于传统的流。不过Channel不能直接访问数据,Channel只能与Buffer进行交互 #### 1、主要的Channel接口实现类 - FileChannel - SocketChannel - ServerSocketChannel - DatagramChannel #### 2、使用方法 ##### 获取通道 - Java针对支持通道的类提供`getChannel()`方法,这些类有: - 本地IO 1. FileInputStream/FileOutputStream 2. RandomAccessFile - 网络IO 1. Socket 2. ServerSocket 3. DatagramSocket - JDK 1.7中的NIO2针对各个通道提供了静态方法`open()` - JDK 1.7中的NIO2中的Files工具类的`newByteChannel()`方法 ##### 使用通道复制文件(本地IO) - 利用Channel完成文件的复制(非直接缓冲区). ``` @Test public void test1() throws IOException { FileInputStream fis = new FileInputStream("JavaNIO.iml"); FileOutputStream fos = new FileOutputStream("JavaNIO2.iml"); // 获取通道 FileChannel inputChannel = fis.getChannel(); FileChannel outputChannel = fos.getChannel(); // 分配指定大小的缓冲区 ByteBuffer buffer = ByteBuffer.allocate(1024); // 将通道内的数据读入缓冲区 while (inputChannel.read(buffer) != -1) { // 将缓冲区内的数据写入通道 buffer.flip(); // 切换为读数据 outputChannel.write(buffer); buffer.clear(); // 清空缓冲区 } // 关闭通道 outputChannel.close(); inputChannel.close(); fos.close(); fis.close(); } ``` - 使用直接缓冲区复制文件(内存映射文件). ``` @Test public void test2() throws IOException { // 使用Open()获取通道 FileChannel inputChannel = FileChannel.open(Paths.get("JavaNIO.iml"), StandardOpenOption.READ); FileChannel outputChannel = FileChannel.open(Paths.get("JavaNIO2.iml"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); // 内存映射文件,和使用allocateDirect()获取内存一样,内存在物理内存中 MappedByteBuffer inputMappedBuffer = inputChannel.map(FileChannel.MapMode.READ_ONLY, 0, inputChannel.size()); MappedByteBuffer outputMappedBuffer = outputChannel.map(FileChannel.MapMode.READ_WRITE, 0, inputChannel.size()); // 直接对缓冲区进行读写操作 byte[] bytes = new byte[inputMappedBuffer.limit()]; inputMappedBuffer.get(bytes); outputMappedBuffer.put(bytes); // 关闭通道 inputChannel.close(); outputChannel.close(); } ``` #### 3、通道之间的数据传输 - 主要方法 - transferFrom() - transferTo() ``` @Test public void test3() throws IOException { // 使用Open()获取通道 FileChannel inputChannel = FileChannel.open(Paths.get("JavaNIO.iml"), StandardOpenOption.READ); FileChannel outputChannel = FileChannel.open(Paths.get("JavaNIO2.iml"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW); // 通道间的数据传输(二用一) // inputChannel.transferTo(0, inputChannel.size(), outputChannel); outputChannel.transferFrom(inputChannel, 0, inputChannel.size()); inputChannel.close(); outputChannel.close(); } ``` #### 4、分散(Scatter)与聚集(Gather) - 分散读取(Scattering Reads): 将通道中的数据分散到多个缓冲区中 - 聚集写入(Gathering Writes):将多个缓冲区内的数据聚集到通道中 #### 5、[字符集](./src/channel/TestCharset.java) > 指定字符集,避免乱码。常用于CharBuffer与ByteBuffer之间。 #### 6、网路IO(核心内容) > 传统IO为阻塞式的,NIO通过选择器实现非阻塞式IO - 核心内容 - Channel - Buffer - Selector ##### 1、[TCP连接](./src/channel/TCPChannel.java) > 主要Channel为SocketChannel与ServerSocketChannel; ##### 2、[UDP连接](./src/channel/UDPChannel.java) > 主要Channel为DatagramChannel ### 3、[管道](./src/pipe/TestPipe.java) > Java NIO 管道是2个线程之间的单向数据连接,Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取