• 5、Channel


        5、Channel

            通道(Channel)用于源节点与目标节点的连接,在Java NIO中负责缓冲区中数据的传输,Channel本身不存储数据,因为需要配合缓冲区进行传输。Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。

            (1)、Channel接口实现类

                ①、FileChannel

                    从文件中读写数据。

                ②、SocketChannel

                    能通过TCP读写网络中的数据。

                ③、ServerSocketChannel

                    可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。

                ④、DatagramChannel

                    能通过UDP读写网络中的数据。

            (2)、获取Channel方式

                ①、getChannel()方法

                    Java针对支持通道的类提供了getChannel()方法。

                    本地IO:FileInputStream/FileOutputStream、RandomAccessFile

                    网络IO:Socket、ServerSocket、DatagramSocket

                ②、在JDK1.7中的NIO.2针对各个通道提供了静态方法open()

                ③、在JDK1.7中的NIO.2的Files工具类的newByteChannel()

            (3)、AbstractSelectableChannel类

                SelectableChannel抽象类,其子类:SocketChannel类、ServerSocketChannel类

    1. public abstract class AbstractSelectableChannel extends SelectableChannel {
    2. /**
    3. * 注册一个选择器并设置监听事件,最后一个参数可以设置共享数据
    4. */
    5. public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { ... }
    6. /**
    7. * 设置阻塞或非阻塞模式,取值false表示采用非阻塞模式
    8. */
    9. public final SelectableChannel configureBlocking(boolean block) throws IOException { ... }
    10. }

            (4)、SocketChannel类

                网络IO通道,具体负责进行读写操作。NIO把缓冲区的数据写入通道,或者把通道里的数据读到缓冲区。

                ①、核心方法

    1. public abstract class SocketChannel extends AbstractSelectableChannel
    2. implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel {
    3. /**
    4. * 获取一个SocketChannel通道
    5. */
    6. public static SocketChannel open() throws IOException { return SelectorProvider.provider().openSocketChannel(); }
    7. /**
    8. * 连接服务器
    9. */
    10. public abstract boolean connect(SocketAddress remote) throws IOException;
    11. /**
    12. * 如果上面的方法连接失败,接下来就要通过该方法完成连接操作
    13. */
    14. public abstract boolean finishConnect() throws IOException;
    15. /**
    16. * 从通道里读数据
    17. */
    18. public abstract int read(ByteBuffer dst) throws IOException;
    19. /**
    20. * 往通道里写数据
    21. */
    22. public abstract int write(ByteBuffer src) throws IOException;
    23. }

            (5)、ServerSocketChannel类

                在服务器端监听新的Socket连接

                ①、核心方法

    1. public abstract class ServerSocketChannel extends AbstractSelectableChannel implements NetworkChannel
    2. {
    3. /**
    4. * 得到一个ServerSocketChannel对象,new ServerSocketChannelImpl()
    5. */
    6. public static ServerSocketChannel open() throws IOException {
    7. return SelectorProvider.provider().openServerSocketChannel();
    8. }
    9. /**
    10. * 设置服务器端端口号
    11. */
    12. public final ServerSocketChannel bind(SocketAddress local) throws IOException
    13. {
    14. return bind(local, 0);
    15. }
    16. /**
    17. * 接收一个连接,返回代表这个连接的通道对象
    18. */
    19. public abstract SocketChannel accept() throws IOException;
    20. }

            (6)、FileChannel类

                ①、transferTo()方法

                    把数据从当前通道复制到目标通道。

    1. /**
    2. * 将字节从此通道的文件传输到给定的可写入字节通道。
    3. * 尝试从该通道文件中的给定position开始读取最多count个字节,并将它们写入目标通道。 调用此方法可能会也可能不会传输所有请求的字节; 是否这样做取决于渠道的性质和状态。 如果此通道的文件包含从给定的position开始的少于count字节,或者目标通道是非阻塞且其输出缓冲区中的count字节少于position ,则传输的字节数少于所请求的字节数。
    4. * @param position - 文件中的位置,从此位置开始传输;必须为非负数
    5. * @param count - 要传输的最大字节数;必须为非负数
    6. * @param target - 目标通道
    7. * @return - 实际已传输的字节数,可能为零
    8. */
    9. public abstract long transferTo(long position, long count, WritableByteChannel target);

                ②、transferFrom()方法

                    从目标通道中复制数据到当前通道。

    1. /**
    2. * 从给定的可读字节通道将字节传输到此通道的文件中。
    3. * 尝试从源通道读取最多count个字节,并从给定的position开始将它们写入此通道的文件。 调用此方法可能会也可能不会传输所有请求的字节; 是否这样做取决于渠道的性质和状态。 如果源通道剩余少于count个字节,或者源通道非阻塞且输入缓冲区中立即可用的字节数少于count少于count字节数。
    4. * @param src - 源通道
    5. * @param position - 文件在转移开始时的位置; 必须是非负面的
    6. * @param count - 要传输的最大字节数; 必须是非负面的
    7. * @return
    8. */
    9. public abstract long transferFrom(ReadableByteChannel src, long position, long count);

                ③、read(ByteBuffer dst)方法

                    从通道读取数据并放到缓冲区中

    public abstract int read(ByteBuffer dst) throws IOException;

                ④、write(ByteBuffer src)方法

                    把缓冲区的数据写到通道中

    public abstract int write(ByteBuffer src) throws IOException;

                ⑤、FileOutputStream、FileInputStream类,内部包含channel变量

    1. public class FileInputStream extends InputStream {
    2. private FileChannel channel = null;
    3. }
    4. public class FileOutputStream extends InputStream {
    5. private FileChannel channel = null;
    6. }

                ⑥、代码实现

    1. /**
    2. * 实现将1.jpg复制,命名为2.jpg
    3. * 使用直接缓冲区完成文件的复制(内存映射文件)
    4. */
    5. public void test1() throws IOException {
    6. FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    7. FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    8. // 内存映射文件
    9. MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
    10. MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE, 0, inChannel.size());
    11. // 直接对缓冲区进行数据的读写操作
    12. byte[] dst = new byte[inMappedBuf.limit()];
    13. inMappedBuf.get(dst);
    14. outMappedBuf.put(dst);
    15. //关闭通道
    16. inChannel.close();
    17. outChannel.close();
    18. }
    19. /**
    20. * 实现将1.jpg复制,命名为2.jpg
    21. * 利用通道直接的数据传输(直接缓冲区)
    22. */
    23. public void test2() throws IOException {
    24. FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
    25. FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.CREATE);
    26. //通道间数据传输
    27. inChannel.transferTo(0, inChannel.size(), outChannel);
    28. outChannel.transferFrom(inChannel, 0, inChannel.size());
    29. //关闭通道
    30. inChannel.close();
    31. outChannel.close();
    32. }

  • 相关阅读:
    leetcode 509. Fibonacci Number(斐波那契数字)
    JSP session的生命周期简介说明
    选择企业网盘:MCN机构如何做出明智的选择?
    ZooKeeper数据模型/znode节点深入
    【在线教育】EasyExcel入门
    新闻轮播图
    充分统计量,因子分解定理与Rao-Blackwewll定理
    如何通过货架电子标签PTL灯光指引拣选优化仓库管理
    软件测试基础内容介绍,7大定律,13大类型
    python版局域网端口扫描
  • 原文地址:https://blog.csdn.net/L_D_Y_K/article/details/126518896