【Netty】NIO 通道 ( Channel ) 组件

举报
韩曙亮 发表于 2022/01/11 00:23:15 2022/01/11
【摘要】 文章目录 I . 通道 ( Channel ) 概念简介II . 通道 ( Channel ) 常用类III . 常用的 通道 ( Channel ) 之 套接字通道 ( SocketChanne...





I . 通道 ( Channel ) 概念简介



NIO 模型中的 通道 ( Channel ) 组件 :


① NIO 双向读写 : NIO 中的通道 ( Channel ) 是可以双向读写的 , 而 BIO 中的 单一流 ( 输入流 / 输出流 ) 只能读或者只能写 ;

② NIO 异步读写 : NIO 中的通道 ( Channel ) 读写时是异步的 , 全程没有阻塞 ;

③ BIO 同步读写 : BIO 中的流 , 读写时都需要阻塞等待对方回应 ;

④ 通道 ( Channel ) 与 缓冲区 ( Buffer ) : 服务器中 , 通道 ( Channel ) 与 缓冲区 ( Buffer ) 一一对应 , 通道可以读取缓冲区中的数据 , 也可以写出数据到缓冲区中 , 这也是双向读写 ;





II . 通道 ( Channel ) 常用类



通道 ( Channel ) 常用类 : Channel 在 Java 语言 NIO 中被定义成接口 , 常用的实现类有如下 :


① FileChannel : 文件通道 , 用于文件的读写 ;

② ServerSocketChannel : 服务器套接字通道 , 其作用与 BIO 中的 ServerSocket 类似 . 用于 TCP 网络通信中读写数据 ;

③ SocketChannel : 套接字通道 , 其作用与 BIO 中的 Socket 类似 , 用于 TCP 网络通信中读写数据 ;

④ DatagramChannel : 数据包通道 , 用于 UDP 网络通信中读写数据 ;





III . 常用的 通道 ( Channel ) 之 套接字通道 ( SocketChannel )



常用的 通道 ( Channel ) 之 网络套接字通道 ( SocketChannel ) :


① ServerSocketChannel : 在服务器端 , 维护一个 ServerSocketChannel 通道 , 客户端请求服务器通信时 , 服务器端线程会给每个客户端创建一个为该客户端服务的 SocketChannel , 之后服务器与客户端 , 都通过该 SocketChannel 进行通信 ;


② ServerSocketChannel 和 SocketChannel 都是抽象类 :

  • ServerSocketChannel 是抽象类 , 其真实实现的类型为 ServerSocketChannelImpl ;
  • SocketChannel 是抽象类 , 其真实类型为 SocketChannelImpl ;




IV . 常用的 通道 ( Channel ) 之 文件通道 ( FileChannel )



常用的 通道 ( Channel ) 之 文件通道 ( FileChannel ) : 主要作用是 读取 , 写入 , 映射 , 操作本地文件 ;


FileChannel 常用方法 : 前两个是 FileChannel 通道与 缓冲区 读写数据 , 后两个是 FileChannel 与其它 通道 读写数据 ;

  • int read(ByteBuffer dst) : 从 FileChannel 通道中读取数据 , 放入 dst 字节缓冲区中 ;
  • int write(ByteBuffer src) : 将 src 缓冲区中的数据 , 写入到 FileChannel 通道中 ;
  • long transferFrom(ReadableByteChannel src, long position, long count) : 将字节数据从 src 通道传输到本 FileChannel 通道中 ;
  • long transferTo(long position, long count, WritableByteChannel target) : 将字节数据从本 FileChannel 通道传输到 target 通道中 ;




V . 文件通道 ( FileChannel ) 写出文件 示例代码



在这里插入图片描述

1 . 示例需求 : 将 “Hello World” 字符串通过 文件通道 ( FileChannel ) 写出到文件中 ;


① 文件通道 ( FileChannel ) 获取 : NIO 中 , 文件通道 ( FileChannel ) 可以从 文件输出流 ( FileOutputStream ) 中进行获取 , 其本质是通过文件输出流 , 向文件中写出数据 ;

整体流程 : 先将 “Hello World” 字符串写入 字节缓冲区 ( ByteBuffer ) , 在将字节缓冲区 ( ByteBuffer ) 中的数据 写出到 文件通道 ( FileChannel ) 中 , 最后通过 文件通道 ( FileChannel ) 将数据写出到文件中 ;


2 . 代码示例 :


package kim.hsl.nio;

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

public class FileChannelDemo {
    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            String hello = "Hello World";

            //1 . FileChannel 可以从 FileOutputStream 中获取
            fos = new FileOutputStream("file.txt");

            //2 . 创建 FileChannel , 从 FileOutputStream 中可以获取到
            //FileChannel 是抽象类 , 实际类型是 FileChannelImpl
            FileChannel fc = fos.getChannel();

            //3 . FileChannel 需要通过 缓冲区 Buffer 才能与数据进行读写交互
            ByteBuffer buffer = ByteBuffer.allocate(32);
            //将数据放入缓冲区中 , flip 方法作用是将 position 位置设置 0
            buffer.put(hello.getBytes());
            buffer.flip();

            //4 . 将 字节缓冲区 ByteBuffer 中的数据写入到 文件通道 FileChannel 中
            fc.write(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

执行结果 : 在代码的 src 目录生成 file.txt 文件 , 内容为 Hello World ;

在这里插入图片描述





VI . 文件通道 ( FileChannel ) 读取文件 示例代码



在这里插入图片描述

1 . 示例需求 : 通过 文件通道 ( FileChannel ) 读取文件中的数据 ;


① 文件通道 ( FileChannel ) 获取 : NIO 中 , 文件通道 ( FileChannel ) 可以从 文件输入流 ( FileInputStream ) 中进行获取 , 其本质是通过文件输入流 , 读取文件中的数据 ;

整体流程 : 先通过文件输入流获取文件通道 ( FileChannel ) , 文件通道 ( FileChannel ) 读取文件数据到 字节缓冲区 ( ByteBuffer ) 中 , 从 字节缓冲区 ( ByteBuffer ) 中获取数据 , 将该数据转为字符串打印出来 ;


2 . 代码示例 :

package kim.hsl.nio;

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

public class FileChannelDemo2 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            //1 . FileChannel 可以从 FileInputStream 中获取
            fis = new FileInputStream("file.txt");

            //2 . 创建 FileChannel , 从 FileInputStream 中可以获取到
            //FileChannel 是抽象类 , 实际类型是 FileChannelImpl
            FileChannel fc = fis.getChannel();

            //3 . FileChannel 需要通过 缓冲区 Buffer 才能与数据进行读写交互
            ByteBuffer buffer = ByteBuffer.allocate(32);

            //4 . 将 字节缓冲区 ByteBuffer 中的数据写入到 文件通道 FileChannel 中
            int len = fc.read(buffer);

            //5 . 将数据从缓冲区中取出
            byte[] stringData = new byte[len];
            //注意 : ByteBuffer 需要 flip 翻转后才能读取
            buffer.flip();
            buffer.get(stringData);

            //6 . byte 数组数据转为字符串并打印出来
            String fileString = new String(stringData);
            System.out.println(fileString);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fis != null)
                    fis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

执行结果 :

Hello World

  
 
  • 1




VII . 文件通道 ( FileChannel ) 使用 缓冲区 拷贝文件 示例代码



在这里插入图片描述

1 . 示例需求 : 通过 文件通道 ( FileChannel ) 与 字节缓冲区 ( ByteBuffer ) 进行文件拷贝 ;


① 文件通道 ( FileChannel ) 获取 : NIO 中 , 文件通道 ( FileChannel ) 可以从 文件输入流 ( FileInputStream ) 中进行获取 , 也可以从 文件输出流 ( FileOutputStream ) 中获取 , 其本质是通过文件输入流 , 读取文件中的数据 ;

整体流程 :

  • 先通过文件输入流获取 输入文件通道 ( FileChannel ) , 通过文件输出流获取 输出文件通道 ( FileChannel ) ;
  • 文件通道 ( FileChannel ) 读取文件数据到 字节缓冲区 ( ByteBuffer ) 中
  • 输入文件通道读取数文件据到缓冲区中 , 输出文件通道写出缓冲区数据到文件中 ;

2 . 代码示例 :

package kim.hsl.nio;

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

public class FileChannelDemo3 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //1 . FileChannel 可以从 FileInputStream 中获取
            fis = new FileInputStream("file.txt");
            fos = new FileOutputStream("file2.txt");

            //2 . 创建 FileChannel , 从 FileInputStream / FileOutputStream 中可以获取到
            //FileChannel 是抽象类 , 实际类型是 FileChannelImpl
            FileChannel fcIn = fis.getChannel();
            FileChannel fcOut = fos.getChannel();

            //3 . FileChannel 需要通过 缓冲区 Buffer 才能 读写文件
            ByteBuffer buffer = ByteBuffer.allocate(1024);

            //4 . 读取 file.txt 文件数据到 字节缓冲区 ByteBuffer , 并写出到 file2.txt 文件中
            //循环退出条件 : 如果 文件 读取完毕, read 方法会返回 -1, 代表读取文件完毕
            while ( (fcIn.read(buffer)) >= 0 ){
                //将 ByteBuffer 中的数据写出 file2.txt 文件中
                //翻转后, 将 position 设置成 0, 才能开始写出
                buffer.flip();
                fcOut.write(buffer);
                //重置标志位, 供下一次循环使用
                buffer.clear();
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fis != null)
                    fis.close();
                if(fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

执行结果 :

在这里插入图片描述





VIII . 文件通道 ( FileChannel ) 直接使用 通道 拷贝文件 示例代码



在这里插入图片描述

1 . 示例需求 : 两个 文件通道 ( FileChannel ) 直接拷贝 ;


① 文件通道 ( FileChannel ) 获取 : NIO 中 , 文件通道 ( FileChannel ) 可以从 文件输入流 ( FileInputStream ) 中进行获取 , 也可以从 文件输出流 ( FileOutputStream ) 中获取 , 其本质是通过文件输入流 , 读取文件中的数据 ;

整体流程 :

  • 先通过文件输入流获取 输入文件通道 ( FileChannel ) , 通过文件输出流获取 输出文件通道 ( FileChannel ) ;
  • 直接将输入通道数据转移到输出通道 , 即可完成拷贝 ;

2 . 代码示例 :

package kim.hsl.nio;

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

public class FileChannelDemo4 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            //1 . FileChannel 可以从 FileInputStream 中获取
            fis = new FileInputStream("file.txt");
            fos = new FileOutputStream("file3.txt");

            //2 . 创建 FileChannel , 从 FileInputStream / FileOutputStream 中可以获取到
            //FileChannel 是抽象类 , 实际类型是 FileChannelImpl
            FileChannel fcIn = fis.getChannel();
            FileChannel fcOut = fos.getChannel();

            //3 .  直接将 fcIn 通道的内容写出到 fcOut 通道
            fcOut.transferFrom(fcIn, 0, fcIn.size());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if(fis != null)
                    fis.close();
                if(fos != null)
                    fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

执行结果 :

在这里插入图片描述

文章来源: hanshuliang.blog.csdn.net,作者:韩曙亮,版权归原作者所有,如需转载,请联系作者。

原文链接:hanshuliang.blog.csdn.net/article/details/106344347

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。