• Java I/O之NIO概念理解


    JDK1.4的java.nio.*包引入了新的Java I/O新类库,其目的在于提高速度。实际上,旧的I/O包已经使用nio重新实现过,以便充分利用这种速度提高,因此即使我们不显式地用nio编码,也能从中受益。

    通道(Channel)和缓冲器(ByteBuffer)

    NIO速度的提高其实来自于所使用的结构更接近于操作系统执行I/O方式:通道和缓冲器。通道和缓冲器的关系你可以这样在脑海里建立一个概念模型:想象一个煤矿,通道就是链接矿藏和外界的矿井,而缓冲器是在矿井运输煤炭的卡车。卡车满载后通过矿井远处到外界,我们就可以从卡车上获取到煤炭。而我们没有直接和通道交互,而只是和缓冲器交互,而通道要么从缓冲器获取数据,要么向缓冲器发送数据。如下图:

    NIO修改了旧IO的三个类用于产生FileChannel:FileInputStream、FileOutputStream和RandomAccessFile。这些都是字节流而不是字符流。我们先通过代码来形象地了解下用法吧。

    //缓冲器
    ByteBuffer buf=ByteBuffer.allocate(1024);
    //输出通道
    FileChannel out=new FileOutputStream("d:"+File.separator+"data.txt").getChannel();
    //数据写入缓冲器
    buf.asCharBuffer().put("this is a demo txt.");
    //通道操作缓冲器
    out.write(buf);
    
    //输入通道
    FileChannel in=new FileInputStream("d:"+File.separator+"data.txt").getChannel();
    //清空缓冲器
    buf.clear();
    //通道操作缓冲器
    in.read(buf);
    //设置缓冲器可读位置
    buf.flip();		
    System.out.println(buf.asCharBuffer());

    输出

    this is a demo txt.


    通道Channel

    通道是缓冲器连接数据源或数据目的地的连接,直接操纵缓冲器读写数据。

    java.nio.channels包中定义了通道API,包括FileChannel、Socket通道SocketChannel、ServerSocket通道ServerSocketChannel、数据报通道DatagramChannel。本篇暂不介绍Socket通道

    Java的通道关系图如下:


    Channel接口的两个最重要的子接口是ReadableByteChannel和WritableByteChannel。

    • ReadableByteChannel定义了一个可从中读取byte数据的Channel接口,该接口定义了read(ByteBuffer dst)方法,该方法把数据源的数据读入指定的ByteBuffer缓冲区中。
    • WritableByteChannel接口声明了write(ByteBuffer dst)方法,该方法把参数指定的ByteBuffer缓冲区中的数据写到数据汇中。

    这里我们不做深入探讨,有兴趣的同学可以直接查看Java源码。


    缓冲器ByteBuffer

    从Java的类库来看,ByteBuffer只是众多Buffer的其中一员:

    这里我也不做深入分析,我们只来简单了解下ByteBuffer从Buffer继承的几个方法clear()、flip()和rewind(),以及ByteBuffer的视图。

    ByteBuffer说白点就是对一个定长数组的包装。里面有几个指针控制读写的位置和范围。数组的长度是capacity,读写的当前位置是position,读写范围的结束地点为limit。position的位置会随着读写向后移动,当到达limit位置时会报出响应的异常。比如读的范围超过了limit,会报BufferUnderflowException,如果写的时候超过了limit,会报BufferOverflowException。position和limit都提供了相应方法设置和获取,使用起来相当灵活。下面的图演示了ByteBuffer的主要结构:


    一般情况下,我们往ByteBuffer写入数据时,会先调用clear方法,将position设置成0,limit设置成capacity,然后开始调用ByteBuffer的各种put方法来塞入数据;当我们从ByteBuffer中读数据时,会先调用ByteBuffer的flip方法将position重置为0、limit设置为当前的position,读取ByteBuffer中的数据。

    常用的缓冲器方法

    static ByteBuffer allocate(int capacity) //分配一个新的字节缓冲区。 
    final Buffer clear()//清除此缓冲区。将位置设置为 0,将限制设置为容量,并丢弃标记。 
    final Buffer flip()//首先将限制设置为当前位置,然后将位置设置为 0。如果已定义了标记,则丢弃该标记。 
    final Buffer rewind()//将位置设置为 0 并丢弃标记。 
    final Buffer mark()//在此缓冲区的当前位置设置标记。 
    final Buffer reset()//将此缓冲区的位置重置为以前标记的位置。

    缓冲器有多个视图,如

    CharBuffer asCharBuffer()

    创建此字节缓冲区的视图,作为 char 缓冲区,新缓冲区的内容将从此缓冲区的当前位置开始。此缓冲区内容的更改在新缓冲区中是可见的,反之亦然;这两个缓冲区的位置、界限和标记值是相互独立的。 

    还有很多视图如:asDoubleBuffer() 、asFloatBuffer() 、asIntBuffer()等等,以及众多方法,再次不意义累述,请查阅JDK API文档。

    本篇博文就此结束,估计没过瘾吧?!其实这里主要是通道和缓冲器的理解,理解后再对照JDK API文档练习即可,熟能生巧。

    出处:http://www.zhaiqianfeng.com    
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    CSS基础
    数据库优化之SQL Server
    压力测试与系统调优
    JBoss架构分析
    JBoss基本配置
    深入了解硬盘结构
    EJB2与EJB3架构对比
    JBoss高级配置
    病毒分类及病毒命名规则详解
    深入讲解防火墙的概念原理与实现
  • 原文地址:https://www.cnblogs.com/zhaiqianfeng/p/4620219.html
Copyright © 2020-2023  润新知