美文网首页
Java NIO(三):FileChannel、SocketCh

Java NIO(三):FileChannel、SocketCh

作者: 聪明的奇瑞 | 来源:发表于2018-03-07 00:54 被阅读66次

    FileChannel

    • 打开 FileChannel,需要通过 InputStream、OutputStream 或 RandomAccessFile 来获取一个 FileChannel 实例
    RandomAccessFile aFile = new RandomAccessFile("data/nio-data.txt", "rw");
    FileChannel inChannel = aFile.getChannel();
    
    • 从 FileChannel 读取数据,需要分配一个 Buffer,在将 FileChannel 中的数据读到 Buffer 中
    ByteBuffer buf = ByteBuffer.allocate(48);
    int bytesRead = inChannel.read(buf);
    
    • 向 FileChannel 写数据
    String str = "abc";
    ByteBuffer byteBuffer = ByteBuffer.allocate(48);
    byteBuffer.put(str.getBytes());
    byteBuffer.flip();
    while (byteBuffer.hasRemaining()) {
        fileChannel.write(byteBuffer);
    }
    
    • 用完 FileChannel 后必须将其关闭
    channel.close();
    
    • 若需要在特定位置进行数据读/写操作可以调用 position() 方法获取 FileChannel 当前位置,也可以设置当前位置(注意:如果将位置设置在文件结束符之后,然后在向通道写数据,文件将撑大到当前位置并写入数据,这可能导致"文件空洞"
    long pos = channel.position();
    channel.position(pos +123);
    
    • 调用 size() 方法返回文件的大小
    long fileSize = channel.size();
    
    • 使用 truncate() 方法截取一个文件,截取文件时文件中指定长度后面的部分将被删除
    channel.truncate(1024);
    
    • force() 方法将通道里尚未写入磁盘的数据强制写到磁盘上,出于性能方面考虑,操作系统将数据缓存在内存中,无法保证写入到 FileChannel 里的数据一定会即时写到磁盘上,force() 方法有一个 boolean 类型的参数,指明是否同时将文件元数据(权限信息等)写到磁盘上
    channel.force(true);
    

    通道间的数据传输

    • FileChannel 的 transferFrom() 方法可以将数据从源通道传输到 FileChannel 中
    try (RandomAccessFile raf = new RandomAccessFile("/Users/linyuan/Documents/字目录.txt", "rw");
        RandomAccessFile toFile = new RandomAccessFile("/Users/linyuan/Documents/toFile.txt", "rw")) {
        FileChannel fromChannel = raf.getChannel();
        FileChannel toChannel = toFile.getChannel();
        long position = 0;
        long count = fromChannel.size();
        // position 表示从 position 处开始向目标文件写入数据,count 表示最多传输的字节数
        // 如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数
        toChannel.transferFrom(fromChannel, position, count);
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    • transferTo() 方法将数据从 FileChannel 传输到其他的 channel 中

    SocketChannel

    • SocketChannel 是一个连接到 TCP 网络套接字的通道
    • 通过 SocketChannel 的 open() 创建 SocketChannel 实例,并通过 connect() 连接服务器
    socketChannel = SocketChannel.open();
    socketChannel.connect(new InetSocketAddress("127.0.0.1", 80));
    

    非阻塞模式

    • 此时调用 connect 方法可能在建立连接前就返回了,为了确定是否建立连接,可以调用 finishConnect 方法
    socketChannel.configureBlocking(false);     // 设置为非阻塞模式
    socketChannel.connect(new InetSocketAddress("http://www.baidu.com", 80));
    while(!socketChannel.finishConnect() ){
        //wait, or do something else...
    }
    

    ServerSocketChannel

    • ServerSocketChannel 是一个服务器端 SocketChannel,监听 TCP 连接通道
    • 通过 ServerSocketChannel 的 open() 创建 ServerSocketChannel 实例,并绑定端口
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    
    • 循环调用 accept() 等待客户端连接,该方法默认为阻塞状态
    while(true){
        SocketChannel socketChannel =serverSocketChannel.accept();
        //do something with socketChannel...
    }
    

    非阻塞模式

    • 在非阻塞模式下 accept 方法会立即返回,如果没有新客户端连接,则返回值为 null,需要检查 SocketChannel 是否为 null
    ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
    serverSocketChannel.socket().bind(new InetSocketAddress(9999));
    serverSocketChannel.configureBlocking(false);   // 设置为非阻塞模式
    while(true){
        SocketChannel socketChannel = serverSocketChannel.accept();
        if(socketChannel != null){
        //do something with socketChannel...
        }
    }
    

    DatagramChannel

    • DatagramChannel 是一个能收发 UDP 数据包的通道,因为 UDP 是无连接的网络,所以不能像其它通道一样读取和写入,只能发送和接收数据包
    • 通过 DatagramChannel 的open() 创建 DatagramChannel 实例,并绑定端口
    DatagramChannel channel = DatagramChannel.open();
    channel.socket().bind(new InetSocketAddress(9999));
    
    • 通过 receive() 接收数据报
    ByteBuffer buf = ByteBuffer.allocate(48);
    channel.receive(buf);
    
    • 通过 send() 发送数据报
    String str = "新的一天";
    ByteBuffer buf = ByteBuffer.allocate(48);
    buf.put(str.getBytes());
    buf.flip();
    channel.send(buf, new InetSocketAddress("localhost", 9999));
    

    连接到特定的地址

    • DatagramChannel 可以“连接”到网络中特定地址,通过 connect 方法,但这种连接并非真正的连接,而是锁住发送的地址,让其只能从特定地址收发数据
    channel.connect(new InetSocketAddress("localhost", 80));
    
    • 当连接后可以使用 read 和 write 方法
    int bytesRead = channel.read(buf);
    int bytesWritten = channel.write(but);
    

    相关文章

      网友评论

          本文标题:Java NIO(三):FileChannel、SocketCh

          本文链接:https://www.haomeiwen.com/subject/duzhfftx.html