通道(Channel)
在NIO程序中服务器端和客户端之间的数据读写不是通过流,而是通过通道来读写的。
通道类似于流,都是用来读写数据的,但它们之间也是有区别的:
-
通道是双向的,即可以读也可以写,而流是单向的,只能读或写
-
通道可以实现异步读写数据
-
通道可以从缓冲区读数据,也可以把数据写入缓冲区
java中channel的相关类在java.nio.channel包下。Channel是一个接口,其常用的实现类有:
-
FileChannel:用于文件的数据读写,其真正的实现类为FileChannelImpl
-
DatagramChannel:用于UDP的数据读写,其真正的实现类为DatagramChannelImpl
-
ServerSocketChannel:用于监听TCP连接,每当有客户端连接时都会创建一个SocketChannel,功能类似ServerSocket,其真正的实现类为ServerSocketChannelImpl
-
SocketChannel:用于TCP的数据读写,功能类似节点流+Socket,其真正的实现类为SocketChannelImpl
FileChannel
FileChannel主要用于对本地文件进行IO操作,如文件复制等。它的常用方法有:
在文件传输流中有个属性channel,它默认是空的,可以通过流中的getChanel()方法根据当前文件流的属性生成对应的FileChannel。
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
channel = FileChannelImpl.open(fd, path, false, true, append, this);
}
return channel;
}
}
}
下面是通道使用的代码实例:
public class NIOChannel {
public static void main(String[] args) throws IOException {
}
//将数据写入目标文件
public static void writeFile() throws IOException{
String str = "Hello, gofy";
//创建文件输出流
FileOutputStream fileOutputStream = new FileOutputStream("f:\\file.txt");
//根据文件输出流生成文件通道
FileChannel fileChannel = fileOutputStream.getChannel();
//创建字节缓冲区,并将字符串转成字节存入
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.put(str.getBytes());
//注意,在存入后需要进行写出操作时,需将缓冲区翻转
byteBuffer.flip();
//将缓冲区数据写入通道
fileChannel.write(byteBuffer);
//将文件输出流关闭(该方法同时会关闭通道)
fileOutputStream.close();
}
//从文件中读取数据
public static void readFile() throws IOException{
//创建文件输入流
File file = new File("f:\\file.txt");
FileInputStream fileInputStream = new FileInputStream(file);
//根据文件输入流生成文件通道
FileChannel fileChannel = fileInputStream.getChannel();
//创建字节缓冲区,大小为文件大小
ByteBuffer byteBuffer = ByteBuffer.allocate((int)file.length());
//将通道数据读入缓冲区
fileChannel.read(byteBuffer);
//同样,在读入后需要取出缓冲区内所有数据时,需将缓冲区翻转
byteBuffer.flip();
System.out.println(new String(byteBuffer.array()));
fileInputStream.close();
}
//将文件数据传输到另一个文件
public static void readAndWriteFile() throws IOException{
//创建文件输入流和文件输出流,并生成对应的通道
FileInputStream fileInputStream = new FileInputStream("file1.txt");
FileChannel inputStreamChannel= fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("file2.txt");
FileChannel outputStreamChannel = fileOutputStream.getChannel();
//创建字节缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//进行数据读取
while (true){
//在读取前需清除缓冲区
byteBuffer.clear();
//将文件输入的通道的数据读入缓冲区
int read = inputStreamChannel.read(byteBuffer);
//当read为-1时,即通道数据已读取完毕
if (read == -1){
break;
}
//将缓冲区翻转后,将缓冲区数据写入文件输出的通道
byteBuffer.flip();
outputStreamChannel.write(byteBuffer);
}
fileInputStream.close();
fileOutputStream.close();
}
//文件的复制粘贴
public static void copyAndPaste() throws IOException{
//复制的文件输入流
FileInputStream fileInputStream = new FileInputStream("f:\\a.jpg");
FileChannel srcChannel = fileInputStream.getChannel();
//粘贴的文件输出流
FileOutputStream fileOutputStream = new FileOutputStream("f:\\b.jpg");
FileChannel targetChannel = fileOutputStream.getChannel();
//使用transferFrom进行复制粘贴
targetChannel.transferFrom(srcChannel, 0, srcChannel.size());
fileInputStream.close();
fileOutputStream.close();
}
}