• ByteBuffer的介绍


    转摘

    有一个问题需要明确:
    为什么要使用bytebuffer,它比byte比起来有什么优点?

    很简单:为了提高IO的效率。怎样提高的,这个还得google一下。

    记住几个标志的含义:
    position[0]:当前指针的位置,也就是接下来要读写的位置。
    limit:限制,一个缓冲区可读写的范围。
    capability:容量,一个缓冲区最多的存放的字节数。
    mark[-1]:标志位,记录当前的位置。

    界限是用来控制当前读写的范围,如果容量为100,界限为10,则位置只能在0-10之间,即只能读写0-10之间的数据。


    几个操作对它们的影响:(操作都会影响到position,clear和flip会影响到limit)
    flip():limit=position, position=0. mark=-1 中文意思是“翻转”。

    rewind():position=0,limit不变,可以用于重复读取一段数据. 扩展所有的数据,中文意思是“倒带”,也就是从头开始别的什么也不变。中文意思是“翻转”,也就是当前指,针在哪就在哪,然后从头开始。mark =-1

     

    clear():position=0,limit=capability,也就是相当于清空了之前的内容,但是ByteBuffer中数组的内容在向里面写入之前是没有改变的.所有的位置与使用ByteBuffer.allocate(int capacity)是一样一样的。


    mark( ) 就是把当前的Position( ) 设置一个标记!

    reset( ) position=mark(); 注意不能为-1 mark位置不变

    在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,都是将它放到缓冲区中。缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。

    buffer其实只是一个美化了的数组。

    状态变量

    跟踪数据的状态情况使buffer可以自己管理数据资源

    position: 其实是指从buffer读取或写入buffer的下一个元素位置。比如,已经写入buffer 3个元素那那么position就是指向第4个位置,即position设置为3(数组从0开始计)。

    limit:还有多少数据需要从buffer中取出,或还有多少空间可以放入。postition总是<=limit。

    capacity: 表示buffer本身底层数组的容量。limit绝不能>capacity。

    filp():作了两件事情:1.将limit指向现在position的位置 2.将position设置为0 (limit=position;position=0)

        这个过程可以使之前buffer写入数据时改变的状态变为可以“准备读取”。因为之前写到buffer中的数据就是position 到 limit-1 两个位置之间(limit指向最后一个数据的后一个位置)。

    clear():

    也作了两件事:1. limit=capacity 2.position=0

    这个过程可以使buffer读取数据时改变的状态改变为“清空并准备写入”。

    访问方法

    以下都以bytebuffer为例

    get():

       前三个get方法是相对读取。就是相对于位置状态来读取数据,并且会改变position位置状态。

       byte get();

       ByteBuffer get(byte dst[]);//读取bytebuffer中数据写入 dst[]

       ByteBuffer get(byte dst[],int offset, int length);

       该读取数据是绝对读取(一个byte),即会忽略limit和position值。并完全绕过了缓冲区的状态统计方法。

       就是说不会改变buffer内部的位置状态。

       byte get(int index);

    put();

       与get类似 前四个put方法是相对读取。即受position 以及limit影响,并且会改变 position。

       ByteBuffer put( byte b );

       ByteBuffer put( byte src[] ); //从src[]写入bytebuffer

       ByteBuffer put( byte src[], int offset, int length );

       ByteBuffer put( ByteBuffer src );

       最后一个是绝对写入 不会影响position等位置状态。

       ByteBuffer put( int index, byte b );

    除了byte的读写还有其他类型的读写方法。并且他们都存在相对以及绝对两类。

    操作的典型使用:

    view plaincopy to clipboardprint?

    1. while (true) {  
    2.      buffer.clear(); // 准备将数据写入buffer
    3. int r = fcin.read( buffer ); // channel读取外部系统的数据并写入 buffer
    4. if (r==-1) {  
    5. break;  
    6.      }  
    7.      buffer.flip(); //准备将数据读出buffer
    8.      fcout.write( buffer ); // channel读取buffer的数据并写到相应的外部系统

    高级应用

    缓存区的分配和包装

    ByteBuffer.allocate(int);方法可以分配(创建)一个byte类型的buffer。

    ByteBuffer.wrap(byte[]);方法可以将一个已有的byte数组包装出一个新的bytebuffer对象。

    后一种方式需要小心处理原来的那个byte数组。因为它可以直接访问了。

    缓冲区的分片

    分片就是建立“子缓冲区”。子缓冲区共享父缓冲区的一部分底层数组位置。

    在某种意义上,子缓冲区就像原来的缓冲区中的一个窗口。

    这样当改变子缓冲区的内容时,父缓冲区的相应位置也会被改变。

    分片操作是根据当前position以及limit的值来确定的。

    buffer.position( 3 );

    buffer.limit( 7 );

    ByteBuffer slice = buffer.slice();

    只读缓冲区

    asReadOnlyBuffer()方法可以返回一个与原buffer对象一样的对象,只是新的buffer对象是只读的。

    直接缓冲区

    sun的定义:给定一个直接字节缓冲区,Java 虚拟机将尽最大努力直接对它执行本机 I/O 操作。也就是说,它会在每一次调用底层操作系统的本机 I/O 操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中(或者从一个中间缓冲区中拷贝数据)。

    创建directbuffer的方式是用ByteBuffer.allocateDirect( int );方法替代ByteBuffer.allocate(int);

    内存影射文件I/O

    它读写要比其他IO快很多.

    他使文件或文件的一部分由内存影射。但是只有操作该部分位置的数据才是以内存方式读写的,而不是整个文件读入内存。(并且他是一个os的底层机制。由os底层异步完成内存与物理磁盘上的数据同步)

    影射文件可以通过FileChannel对象的map方法得到。

    比如以下就是将一个文件的前1024个字节影射到内存,并创建一个MappedByteBuffer对象返回出来。MappedByteBuffer是ByteBuffer的一个子类。

    MappedByteBuffer mbb = fc.map( FileChannel.MapMode.READ_WRITE, start, size );

  • 相关阅读:
    JQ_简单版图像点击切换(不是无缝)
    CSS_最简单,最难的对齐,以及其他
    JS_简单无缝图片滚动
    baiduMap
    JS_cookie
    JQ_简单图片无缝滚动
    JS_Flash调用函数
    高性能WEB开发(6) web性能测试工具推荐
    字符编码笔记:ASCII,Unicode和UTF8
    MIME
  • 原文地址:https://www.cnblogs.com/bearlovejiajia/p/3848524.html
Copyright © 2020-2023  润新知