常用的Channel有哪些?
(1)FileChannel文件通道,用于文件的数据读写; (2)SocketChannel套接字通道,用于Socket套接字TCP连接的数据读写; (3)ServerSocketChannel服务器套接字通道(或服务器监听通道),允许我们监听TCP 连接请求,为每个监听到的请求,创建一个SocketChannel套接字通道; (4)DatagramChannel数据报通道,用于UDP协议的数据读写。
FileChannel:文件通道,用于文件的数据读写。通过以下方式获取FileChannel对象: 通过FileChannel可以读写文件的内容,例如:
RandomAccessFile file = new RandomAccessFile("file.txt", "rw");
FileChannel channel = file.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = channel.read(buffer);
while (bytesRead != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = channel.read(buffer);
}
下面使用FileChannel实现了文件复制的功能
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
FileChannel channelIn = fis.getChannel();
FileChannel channelOut = fos.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (channelIn.read(buffer) != -1) {
buffer.flip();
channelOut.write(buffer);
buffer.clear();
}
fis.close();
fos.close();
channelIn.close();
channelOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
实现文件的复制:
- 创建一个 FileInputStream 对象和一个 FileOutputStream 对象,分别通过这两个对象获取对应的 FileChannel 对象。
- 创建一个 ByteBuffer 对象,从 FileInputStream 的 FileChannel 中读取数据,并将数据写入 ByteBuffer 中。
- 使用 flip() 方法翻转 ByteBuffer,将 ByteBuffer 从写模式切换到读模式。
- 使用 write() 方法从 FileOutputStream 的 FileChannel 中将数据写入文件。
- 重复步骤 2-4,直到读取完整个文件。
- 关闭打开的文件和通道。
- 捕获并处理可能出现的异常。
除了FileChannel的通道操作外,还需要注意代码执行过程中隐藏的ByteBuffer的模式切 换。由于新建的ByteBuffer是写入模式,才可作为inChannel.read(ByteBuffer)方法的参数, inChannel.read(…)方法将从通道inChannel读到的数据写入到ByteBuffer。然后,需要调用 缓冲区的flip方法,将ByteBuffer从写入模式切换成读取模式,才能作为outchannel.write (ByteBuffer)方法的参数,以便从ByteBuffer读取数据,最终写入到outchannel输出通道。
SocketChannel:套接字通道,用于Socket套接字TCP连接的数据读写。通过以下方式获取SocketChannel对象: 通过SocketChannel可以进行TCP连接,例如:
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("localhost", 8080));
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.put("Hello, Server.".getBytes());
buffer.flip();
channel.write(buffer);
ServerSocketChannel:服务器套接字通道(或服务器监听通道),允许我们监听TCP连接请求,为每个监听到的请求,创建一个SocketChannel套接字通道。通过以下方式获取ServerSocketChannel对象: 通过ServerSocketChannel可以监听TCP连接请求,例如:
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(8080));
while (true) {
SocketChannel client = serverSocketChannel.accept();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = client.read(buffer);
while (bytesRead != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
System.out.print((char) buffer.get());
}
buffer.clear();
bytesRead = client.read(buffer);
}
}
使用SocketChannel发送文件的实践案例
这段代码实现了将本地的一个文件通过SocketChannel传输到指定的主机和端口。其中,使用了FileChannel的transferTo方法,该方法可以将文件从FileChannel传输到SocketChannel中。
需要注意的是,在传输文件之前需要先获取文件的大小和文件通道,传输过程中需要记录已经传输的大小,并在传输完成后关闭通道。
下面是一个将本地文件通过SocketChannel传输到指定主机和端口的实现。
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("localhost", 8080));
socketChannel.configureBlocking(true);
String filePath = "D:\\\\file.txt";
File file = new File(filePath);
FileInputStream fis = new FileInputStream(file);
FileChannel fileChannel = fis.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = 0;
long transferSize = 0;
long fileSize = file.length();
long startTime = System.currentTimeMillis();
while ((bytesRead = fileChannel.read(buffer)) != -1) {
buffer.flip();
while (buffer.hasRemaining()) {
transferSize += socketChannel.write(buffer);
}
buffer.clear();
}
fileChannel.close();
fis.close();
socketChannel.close();
long endTime = System.currentTimeMillis();
System.out.println("Time used:" + (endTime - startTime) + "ms");
}
这段代码使用了FileInputStream和FileChannel来读取本地文件,并使用SocketChannel将读取到的数据传输到指定的主机和端口。需要注意的是,这里使用了一个循环来不断读取文件并将数据写入SocketChannel,直到文件全部传输完成。
DatagramChannel:数据报通道,用于UDP协议的数据读写。通过以下方式通过DatagramChannel对象,通过DatagramChannel可以进行UDP数据传输,例如:
DatagramChannel channel = DatagramChannel.open();
ByteBuffer buffer = ByteBuffer.wrap("Hello, Server.".getBytes());
channel.send(buffer, new InetSocketAddress("localhost", 8080));