四个Channel的讲解

本文详细介绍了Java NIO中的四个关键Channel:FileChannel用于高效读写文件,支持直接内存和transferTo方法;SocketChannel提供阻塞和非阻塞模式,适合与Selector结合管理多个连接;SocketServerChannel处理服务器端连接,同样具备阻塞和非阻塞模式;DatagramChannel则基于UDP协议,适用于UDP通信场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.FileChannel

1.读的例子

 public static void read(String fileName) throws IOException {
         //第一种获取FileChannel的方法
       /* RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
        FileChannel fileChannel1= randomAccessFile.getChannel();*/

        //第二种获取FileChannel的方法
        File file = new File(fileName);
        FileInputStream inputStream = new FileInputStream(file);
        FileChannel fileChannel2=inputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(2);
        int read = fileChannel2.read(byteBuffer);
        while (read!=-1){
             byteBuffer.flip();
             System.out.println(Charset.forName("GBK").decode(byteBuffer).toString());
             byteBuffer.clear();
             read = fileChannel2.read(byteBuffer);
        }
        //直接内存 https://blog.youkuaiyun.com/qq_30055391/article/details/85009551讲过相关知识
        DirectBuffer directBuffer=(DirectBuffer)byteBuffer;
        directBuffer.cleaner().clean();
        fileChannel2.close();
        inputStream.close();
    }

2.写的例子

public  static  void  write(String fileName) throws IOException {
        File file = new File(fileName);
        //如果需要不覆盖 需要在后面加上 true参数
        FileOutputStream fileOutputStream = new FileOutputStream(file,true);
        FileChannel fileChannel = fileOutputStream.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(20);
        byteBuffer.put("new new new".getBytes());
        //对 position和limit进行设置 https://blog.youkuaiyun.com/qq_30055391/article/details/85009551讲过
        byteBuffer.flip();
        //因为不知道buffer里面的值会不会一下子写完 ,所以循环判断
        while (byteBuffer.hasRemaining()){
            fileChannel.write(byteBuffer);
            //把channel里面的数据只保留前3位 后面的数据截掉 例子里面只会写到文件上面一个new
            fileChannel.truncate(3);
            System.out.println(fileChannel.size());
            //强制把fileChannel里面的数据写到磁盘上面 因为有可能不是马上写入到硬盘上面的文件上面
            fileChannel.force(true);
        }
        fileChannel.close();
        fileOutputStream.close();
    }

3.什么时候该使用NIO?

如果你对读取或者写入文件的速度要求特别高,可以使用NIO里面的直接内存。
如果需要文件复制,可以使用NIO里面Channel的transferTo方法,比较方便。
如果你需要读取足够大(超过1个G的文件),在JVM内存吃紧的情况下可以使用NIO里面的MappedByteBuffer(基于虚拟内存)有兴趣可以看一下 。

2.SocketChannel

阻塞模式下的例子

  public static void  testBlock() throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        //绑定ip和端口号
        socketChannel.connect(new InetSocketAddress("10.252.69.254",5049));

        ByteBuffer byteBuffer = ByteBuffer.allocate(40);
        //阻塞到数据被读入buffer
        int alreadyread = socketChannel.read(byteBuffer);

        ByteBuffer byteBufferWrite = ByteBuffer.allocate(40);
        byteBuffer.put("write content".getBytes());
         while (byteBufferWrite.hasRemaining()){
            //阻塞到数据写入channel
            int alreadyWrite =socketChannel.write(byteBuffer);
        }
         socketChannel.close();
    }

非阻塞模式下的例子

 public void  testNoBlock() throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        //绑定ip和端口号
        socketChannel.connect(new InetSocketAddress("10.252.69.254",5049));
        //设置为非阻塞模式
        socketChannel.configureBlocking(false);
        ByteBuffer byteBuffer = ByteBuffer.allocate(40);
        //阻塞到数据被读入buffer
        int alreadyread = socketChannel.read(byteBuffer);
        //非阻塞模式下read方法会立即返回 所以要判断是否全部读取完毕
        while (alreadyread!=-1){
            socketChannel.read(byteBuffer);
        }
        ByteBuffer byteBufferWrite = ByteBuffer.allocate(40);
        byteBuffer.put("write content".getBytes());
        byteBuffer.flip();
        int alreadyWrite =socketChannel.write(byteBuffer);
        // 非阻塞write也会立即返回 所以要判断是否写入完成
        while (alreadyWrite!=-1){
            //阻塞到数据写入channel
            alreadyWrite =socketChannel.write(byteBuffer);
        }
        socketChannel.close();
    }

和传统的socket编程最大的区别就是提供了非阻塞的模式。并且可以跟selector结合实现管理多个端口的socket。但是实际情况用的不多。

3.SocketServerChannel

阻塞模式

    public static void testServeSocketBlocking() throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //绑定端口号
        serverSocketChannel.socket().bind(new InetSocketAddress(5089));
        ByteBuffer byteBuffer = ByteBuffer.allocate(50);
        try {
            while (true) {
            //阻塞的
                SocketChannel socketChannel = serverSocketChannel.accept();
                int a = socketChannel.read(byteBuffer);
                while (a != -1) {
                    byteBuffer.flip();
                    System.out.println(socketChannel.getLocalAddress() + ":" + Charset.forName("utf-8").decode(byteBuffer).toString());
                    byteBuffer.compact();
                    a = socketChannel.read(byteBuffer);
                }
            }
        } finally {
            serverSocketChannel.close();
        }

    }

非阻塞模式 修改

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);

while(true){
//非阻塞直接返回  没有就直接返回null
    SocketChannel socketChannel =
            serverSocketChannel.accept();

    if(socketChannel != null){
        //do something with socketChannel...
    }
}

#4.DatagramChannel
基于UDP协议的channel。

    public void udpTest() throws IOException {
        //UDP 协议下不需要连接 数据是按块接收的
        DatagramChannel dataProgramChanne = DatagramChannel.open();
        //接收数据
        dataProgramChanne.bind(new InetSocketAddress(8888));
        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        //如果数据包的数据过大,那么就会发生数据丢失
        dataProgramChanne.receive(buf);

        //发送数据
        dataProgramChanne.connect(new  InetSocketAddress("jenkov.com", 80));
        int bytesRead = dataProgramChanne.read(buf);
        int bytesWritten = dataProgramChanne.write(buf);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值