NIO流之通道

本文深入探讨了Java NIO中的Channel概念,包括其在I/O操作中的角色、各种Channel接口的功能,以及FileChannel的使用方法,如读写操作、缓冲区管理等,展示了NIO在提高I/O效率方面的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计算机里的通道

1.传输信息的数据通道。

2.计算机系统中传送信息和数据的装置。主要有主存储器读写通道和输出,输出通道。能接收中央处理器的命令,独立执行通道程序。

NIO技术中的数据要放在缓冲区中进行管理,再使用通道将缓冲区中的数据传输到目的地。

Channel接口的继承结构


  1. AutoCloseable接口强调的是try()结合实现自动关闭,该接口针对任何资源,不仅仅是IO.
  2. AutoCloseable接口的作用是关闭IO流,释放系统资源。
  3. Channel是用于I/O操作的连接,代表数据到硬件设备,文件,网络套接字的连接。
  4. AsynchronousChannel接口的主要作用使通道支持异步I/O操作,并且是线程安全。
  5. AsynchronousByteChannel接口的主要作用使通道支持异步I/O操作,操作单位为字节。
  6. ReadableByteChannel接口是使通道允许对字节进行读操作,且只允许一个读操作在进行。
  7. ScatteringByteChannel接口的主要作用是可以从通道读取字节到多个缓冲区。
  8. WritableByteChannel接口的主要作用是使通道允许对字节进行写操作。
  9. GatheringByteChannel接口是可以将多个缓冲区中的数据写入通道。
  10. ByteChannel接口的主要作用是将ReadableByteChannel与WritableByteChannel的规范进行了统一。
  11. SeekableByteChannel接口的主要作用是在字节通道中维护position,以及允许position发生改变。
  12. NetworkChannel接口的主要作用是使通道与Socket进行关联,是通道中的数据能在Socket技术上进行传输。
  13. MulticastChannel接口的主要作用是使通道支持IP多播。IP多播就是将多个主机地址进行打包,形成一个组,然后将报文向这个组发送,也就相当于同时向多个主机传输数据。
  14. InterruptibleChannel接口的作用是使通道能以异步的方式进行关闭与中断。
  15. AbstractInterruptibleChannel类的主要作用是提供一个可以被中断的通道的基本实现类。

   16.FileChannel类主要作用是读取,写入,映射和操作文件的通道,该通道永远是阻塞的操作。


重点讲述FileChannel类的使用:

写操作:将remaining字节序列从给定的缓冲区写入此通道的当前位置(position),此方法的行为与WritableByteChannel接口所指定的行为完全相同,该方法是同步的,返回值代表写入的字节数。

import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Main {
	public static void main(String[] args) throws IOException {
		FileOutputStream fosRef = new FileOutputStream("D:\\a.txt");
		FileChannel fileChannel = fosRef.getChannel();
		ByteBuffer buffer = ByteBuffer.wrap("abcde".getBytes());
		fileChannel.write(buffer);
	}
}

读操作:将字节序列从此通道的当前位置(position)读入给定的缓冲区的当前位置(position),此方法的行为与ReadableByteChannel接口所指定的行为完全相同,该方法是同步的,返回值代表读取的字节数,如果该通道已到达流的末尾,则返回-1。

import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class Main {
	public static void main(String[] args) throws IOException {
		FileInputStream fisRef = new FileInputStream("D:\\a.txt");
		FileChannel fileChannel = fisRef.getChannel();
		ByteBuffer byteBuffer = ByteBuffer.allocate(5);
		fileChannel.read(byteBuffer);
		byteBuffer.clear();
		byte[] byteArray = byteBuffer.array();
		for(int i = 0; i < byteArray.length; i++){
			System.out.print((char)byteArray[i]);
		}
		fileChannel.close();
		fisRef.close();
	}
}

上面都是通过间接获取输入输出流的通道,我们也可以直接获取文件通道。

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class OpenFile {
	public static void main(String[] args) throws IOException{
		File file = new File("D:\\b.txt");
		Path path = file.toPath();
		FileChannel fileChannel1 = FileChannel.open(path, StandardOpenOption.CREATE, StandardOpenOption.WRITE);
		fileChannel1.close();
		
		FileChannel fileChannel2 = FileChannel.open(path, StandardOpenOption.APPEND);//在文件末尾追加,类似于StringBuffer.append.
		fileChannel2.write(ByteBuffer.wrap("12345".getBytes()));
		fileChannel2.close();
		
		FileChannel fileChannel3 = FileChannel.open(path, StandardOpenOption.READ);
		ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length());
		fileChannel3.read(byteBuffer);
		fileChannel3.close();
		byteBuffer.clear();//恢复默认状态
		for(int i = byteBuffer.position(); i < byteBuffer.limit(); i++)
			System.out.print((char)byteBuffer.get(i));
		
	}

}

在大部分情况下,FileChannel的效率并不比使用InputStream或OutputStream高很多,因为NIO的出现是为了解决操作I/O线程堵塞的问题,使用NIO就把进程变成了非堵塞,这样就提高了运行效率。NIO中非堵塞的特性是与Socket有关的通道进行实现的,接下来将会介绍Socket网络编程。

### Java NIO 的使用教程及示例 Java NIO 是一种高效的输入/输出模型,它通过通道(Channel)、缓冲区(Buffer)以及选择器(Selector)来实现高性能的数据读写操作。以下是关于 Java NIO 的详细介绍及其实际应用。 #### 1. 基本概念 Java NIO 提供了一种全新的方式来进行文件和网络数据的操作。其核心组件包括: - **Channel**: 数据传输的核心接口,类似于传统 IO 中的 Stream。常见的 Channel 实现有 `FileChannel` 和 `SocketChannel` 等[^1]。 - **Buffer**: 数据容器,在 NIO 中所有的数据都必须先放入 Buffer 中才能被 Channel 处理。常用的 Buffer 类型有 `ByteBuffer`, `CharBuffer`, `IntBuffer` 等。 - **Selector**: 负责监控多个 Channel 上的事件(如连接打开、数据到达等),并提供多路复用的功能[^3]。 这些组件共同构成了 Java NIO 的基础架构。 #### 2. 文件读写的简单示例 下面是一个简单的例子,展示如何利用 FileChannel 进行文件的读取与写入操作。 ```java import java.nio.file.*; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; public class FileReadWriteExample { public static void main(String[] args) throws Exception { Path path = Paths.get("example.txt"); try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) { ByteBuffer buffer = ByteBuffer.allocate(1024); int bytesRead = channel.read(buffer); // 将数据从 Channel 读到 Buffer while (bytesRead != -1) { // 当没有更多数据可读时返回 -1 buffer.flip(); // 切换为读模式 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); // 输出字符 } buffer.clear(); // 清空 Buffer 准备下一次读取 bytesRead = channel.read(buffer); } } // 写入文件的例子 String content = "This is a test."; ByteBuffer writeBuffer = ByteBuffer.wrap(content.getBytes()); try (FileChannel outChannel = FileChannel.open(path, StandardOpenOption.WRITE, StandardOpenOption.CREATE)) { outChannel.write(writeBuffer); // 将 Buffer 写入 Channel } } } ``` 上述代码展示了如何使用 `FileChannel` 来完成文件的内容读取和写入过程。 #### 3. 非阻塞服务器端编程实例 另一个重要的场景是非阻塞式的网络通信。这里给出一个基于 Selector 的非阻塞 TCP Server 示例。 ```java import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set; public class NonBlockingServer { private final int port; public NonBlockingServer(int port) { this.port = port; } public void start() throws IOException { Selector selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.configureBlocking(false); InetSocketAddress address = new InetSocketAddress(port); serverChannel.socket().bind(address); serverChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("Listening on port " + port); while (true) { selector.select(); Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { handleAccept(key, selector); } else if (key.isReadable()) { handleMessage(key); } keyIterator.remove(); } } } private void handleAccept(SelectionKey key, Selector selector) throws IOException { SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept(); clientChannel.configureBlocking(false); clientChannel.register(selector, SelectionKey.OP_READ); System.out.println("Client connected."); } private void handleMessage(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer readBuffer = ByteBuffer.allocate(1024); int numRead = -1; try { numRead = socketChannel.read(readBuffer); } catch (IOException e) { System.err.println("Error reading from client: " + e.getMessage()); key.cancel(); return; } if (numRead == -1) { closeConnection(socketChannel, key); } else { processMessageAndRespond(socketChannel, readBuffer); } } private void closeConnection(SocketChannel socketChannel, SelectionKey key) throws IOException { System.out.println("Closing connection with client..."); key.cancel(); socketChannel.close(); } private void processMessageAndRespond(SocketChannel socketChannel, ByteBuffer buffer) throws IOException { buffer.flip(); CharBuffer charBuffer = Charset.defaultCharset().decode(buffer); System.out.println("Received message: " + charBuffer.toString()); String response = "Echo: " + charBuffer.toString(); byte[] responseBytes = response.getBytes(Charset.defaultCharset()); ByteBuffer outputBuffer = ByteBuffer.wrap(responseBytes); socketChannel.write(outputBuffer); buffer.compact(); } public static void main(String[] args) throws IOException { new NonBlockingServer(8080).start(); } } ``` 这段程序创建了一个能够同时处理多个客户端请求的服务端应用程序。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值