zoukankan      html  css  js  c++  java
  • 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 );

  • 相关阅读:
    【Nginx】ngx_event_core_module模块
    ELMAH--Using HTTP Modules and Handlers to Create Pluggable ASP.NET Components 77 out of 90 rated th
    nyist oj 214 单调递增子序列(二) (动态规划经典)
    java 入门书籍(java7)
    ARCGIS将WGS84坐标投影到高斯平面
    【linux】linux下对java程序生成dump文件,并使用IBM Heap Analyzer进行分析,查找定位内存泄漏的问题代码
    【springboot】【socket】spring boot整合socket,实现服务器端两种消息推送
    【linux】linux修改open file 大小
    【docker】docker限制日志文件大小的方法+查看日志文件的方法
    【docker】docker部署spring boot服务,但是docker logs查看容器输出控制台日志,没有日志打印,日志未打印,docker logs不打印容器日志
  • 原文地址:https://www.cnblogs.com/bearlovejiajia/p/3848524.html
Copyright © 2011-2022 走看看