基本介绍
1.NIO的通道类(Channel)似于流,或者理解为一个连接,但有些区别如下
-
通道可以同时进行读写,而流只能读或者只能写
-
通道可以实现异步读写数据
-
通道可以从缓冲读数据,也可以写数据到缓冲:
2.BIO 中的 stream 是单向的,例如 FileInputStream 对象只能进行读取数据的操作,而 NIO 中的通道(Channel)是双向的,可以读操作,也可以写操作。效率也就提高了
3.Channel在NIO中是一个接口public interface Channel extends Closeable{}
4.常用的 Channel 类有:FileChannel、DatagramChannel、ServerSocketChannel 和 SocketChannel。【ServerSocketChanne 类似 ServerSocket , SocketChannel 类似 Socket】
5.FileChannel 用于文件的数据读写,DatagramChannel 用于 UDP 的数据读写,ServerSocketChannel 和 SocketChannel 用于 TCP 的数据读写。
FileChannel 类
FileChannel主要用来对本地文件进行 IO 操作,真正的实现类是FileChannelImpl,常见的方法有
- public int read(ByteBuffer dst) ,从通道读取数据并放到缓冲区中
- public int write(ByteBuffer src) ,把缓冲区的数据写到通道中
- public long transferFrom(ReadableByteChannel src, long position, long count),从目标通道中复制数据到当前通道
- public long transferTo(long position, long count, WritableByteChannel target),把数据从当前通道复制给目标通道
FileChannel 案例
本地文件写数据
/**
* @author TAO
* @description: 本地文件写数据
* @date 2021/6/8 0:02
*/
public class NIOFileChannel01 {
public static void main(String[] args) throws IOException {
String str = "hello Netty";
//创建一个输出流 -> channel
FileOutputStream fileOutputStream = new FileOutputStream("./file01.txt");
//通过fileOutputStream 获取 对应的FileChannel
//这个fileChannel 真实类型是 FileChannelImpl
FileChannel fileChannel = fileOutputStream.getChannel();
//创建一个缓冲区ByteBuffer
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//将 str 放入 byteBuffer
byteBuffer.put(str.getBytes());
//对buffer 进行反转
byteBuffer.flip();
//将byteBuffer 数据写入到fileChannel
fileChannel.write(byteBuffer);
fileChannel.close();
}
}
在fileOutputStream中就包括了Channel,我们可以理解为在我们Java原生输出对象中就包含了Channel
本地文件读数据
/**
* @author TAO
* @description: 本地文件读数据
* @date 2021/6/8 0:02
*/
public class NIOFileChannel02 {
public static void main(String[] args) throws Exception {
//创建文件输入流
File file = new File("./file01.txt");
FileInputStream fileInputStream = new FileInputStream(file);
//通过fileOutputStream 获取 对应的FileChannel
//这个fileChannel 真实类型是 FileChannelImpl
FileChannel fileChannel = fileInputStream.getChannel();
//创建一个缓冲区ByteBuffer
ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());
//将通道的数据读取到Buffer
fileChannel.read(byteBuffer);
//将 byteBuffer 的字节数据转换为String
System.out.println(new String(byteBuffer.array()));
fileInputStream.close();
}
}
使用一个Buffer完成文件读取
/**
* @author TAO
* @description: 使用一个Buffer完成文件读取
* @date 2021/6/21 1:10
*/
public class NIOFileChannel03 {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("./file01.txt");
FileChannel fileChannel1 = fileInputStream.getChannel();
FileOutputStream fileOutputStream = new FileOutputStream("./file02.txt");
FileChannel fileChannel2 = fileOutputStream.getChannel();
ByteBuffer byteBuffer = ByteBuffer.allocate(512);
while (true) {
byteBuffer.clear();//TODO 必须清空buffer 否则red是0 导致死循环
int red = fileChannel1.read(byteBuffer);
System.out.println("red===>"+red);
if (red == -1) {//表示读完
break;
}
//将buffer 中的数据写入到fileChannel2 --2.txt
byteBuffer.flip();
fileChannel2.write(byteBuffer);
}
//关闭相关流
fileInputStream.close();
fileOutputStream.close();
}
}
拷贝文件transferFrom 方法
/**
* @description: 拷贝文件transferFrom 方法
* @author TAO
* @date 2021/6/21 1:25
*/
public class NIOFileChannel04 {
public static void main(String[] args) throws IOException {
//创建相关流
FileInputStream fileInputStream = new FileInputStream("./test1.png");
FileOutputStream fileOutputStream = new FileOutputStream("./test2.png");
//获取各个流对应的FileChannel
FileChannel sourceCh = fileInputStream.getChannel();
FileChannel destCh = fileOutputStream.getChannel();
//使用transferFrom完成拷贝
destCh.transferFrom(sourceCh, 0, sourceCh.size());
//关闭相关通道和流
sourceCh.close();
destCh.close();
fileInputStream.close();
fileOutputStream.close();
}
}