Netty剖析之NIO-Channel

什么是Channel?

Channel即通道的意思,NIO的通道类似于流,但有如下区别:

  • 通道可以同时进行读写操作,而流同一时刻只能读或者写
  • 通道可以实现异步读写数据,而流只可同步操作
  • 通道可以从缓冲区读数据,也可以写数据到缓冲区

BIO中的流是单向的,例如FileInputStream对象只能进行读取数据的操作,而NIO中的通道(Channel)是双向的,既可以读也可以写;

Channel在NIO中是一个接口(public interface Channel extends Closeable),常用的实现类有FileChannel、DatagramChannel、ServerSocketChannel、SocketChannel,SocketChannel相当于BIO中的Socket,ServerSocketChannel相当于ServerSocket;

FileChannel用于文件的读写操作,DatagramChannel用于UDP的数据读写,ServerSocketChannel和SocketChannel用于TCP的数据读写;

Channel需要与缓冲区配合使用

FileChannel常用方法

方法名 描述
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写入数据

public class FileChannelWrite {

    public static void main(String[] args) throws Exception{
        String str = "hello 2020";

        // 创建一个输出流
        FileOutputStream fileOutputStream = new FileOutputStream("d:\\test.txt");

        // 通过fileOutputStream获取fileChannel
        FileChannel fileChannel = fileOutputStream.getChannel();

        // 创建一个缓冲区byteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(str.length());

        // 将字符串放入缓冲区
        byteBuffer.put(str.getBytes());

        // 前面是写操作,此时需要将缓冲区的数据写入到fileChannel,
        // 对于fileChannel来说是读操作,所以此时需要对缓冲区进行反转
        byteBuffer.flip();

        // 将缓冲区的数据写入fileChannel
        fileChannel.write(byteBuffer);

        // 关闭输出流,也可单独关闭fileChannel -> fileChannel.close();
        fileOutputStream.close();
    }
}

FileChannel读取数据

public class FileChannelRead {

    public static void main(String[] args) throws Exception{
        // 创建一个输入流
        File file = new File("d:\\test.txt");
        FileInputStream fileInputStream = new FileInputStream(file);

        // 通过fileInputStream获取fileChannel
        FileChannel fileChannel = fileInputStream.getChannel();

        // 创建一个缓冲区byteBuffer
        ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length());

        // 将通道中的数据读入到缓冲区
        fileChannel.read(byteBuffer);

        System.out.println(new String(byteBuffer.array()));

        // 关闭输出流,也可单独关闭fileChannel -> fileChannel.close();
        fileInputStream.close();
    }
}

FileChannle从A文件读取内容并写入到B文件

public class FileChannelReadWrite {

    public static void main(String[] args) throws Exception{
        FileInputStream fileInputStream = new FileInputStream("d:\\test.txt");
        FileChannel inputStreamChannel = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream("d:\\out.txt");
        FileChannel outputStreamChannel = fileOutputStream.getChannel();

        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        while (true) {

            // 清空buffer
            byteBuffer.clear();

            int read = inputStreamChannel.read(byteBuffer);
            if(read == -1){
                break;
            }

            // 将buffer中的数据写入到outputStreamChannel
            byteBuffer.flip();
            outputStreamChannel.write(byteBuffer);
        }

        fileInputStream.close();
        fileOutputStream.close();
    }
}

FileChannel使用transferFrom拷贝文件

public class FileChannelTransferFrom {

    public static void main(String[] args) throws Exception {
        FileInputStream fileInputStream = new FileInputStream("d:\\Koala.jpg");
        FileChannel inputStreamChannel = fileInputStream.getChannel();

        FileOutputStream fileOutputStream = new FileOutputStream("d:\\Koala_bak.jpg");
        FileChannel outputStreamChannel = fileOutputStream.getChannel();

        // 使用transferFrom进行copy
        outputStreamChannel.transferFrom(inputStreamChannel, 0, inputStreamChannel.size());

        // 关闭流
        fileInputStream.close();
        fileOutputStream.close();

    }
}
发布了107 篇原创文章 · 获赞 19 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/chen_changying/article/details/104128179