NIO的Buffer的相关操作

1、Buffer的创建

Buffer的创建可以通过两种方式。使用静态方法allocate()从堆中分配缓冲区,或者是一个既有的数组中创建缓冲区:

    //从堆中分配
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    //从既有的数组中创建
    byte array[] = new byte[1024];
    ByteBuffer buffer = ByteBuffer.wrap(array);

2、重置和清空缓冲区

Buffer 还提供了一些用于重置和清空Buffer状态的函数,如下:

public final Buffer rewind();
public final Buffer clear();
public final Buffer flip()
以上的三个函数有着类似的功能,它们重置了Buffer对象。这里所谓的重置,只是指重置了Buffer的各项标志位,并不真正清空Buffer的内容。3个函数的功能上也有所不同。
函数rewind将position置零,并清除标志位(mark)。它的作用在于为提取Buffer的有效数据做准备:
    out.write(buf) ;        //从Buffer读取数据写入channel
    buf.rewind();           //回滚Buffer
    buf.get(array);        //将Buffer的有效数据复制到数组中。

函数clear()也将Position置零,同时将Limit设置为capacity的大小,并清除了标志(mark)。由于清空了Limit,因此便无法得知Buffer内哪些数据是真实有效的。这个方法用于为重新写Buffer做准备:
    buf.clear();        //为读入数据到buffer做准备。
    in.read(buf);    //从通道读入数据

函数flip()先将limit设置到position所在位置,然后将Position置零,并清除标志位mark.它通常在读写转换时使用。

    buf.put(magic);    //将magic数组写入buffer
    in.read(buf);        //从通道读入给定信息,存放到Buffer中。
    buf.flip();    //将Buffer从写状态转为读状态
    out.write(buf);    //将magic和in通道中读入的信息,写到通道out中。

3、读/写缓冲区

对Buffer进行读写操作是Buffer最为重要的操作。以ByteBuffer为例,JDK提供了以下常用读写操作:

public byte get();            //返回当前postion上的数据,并将positin位置向后移一位

public ByteBuffer get(byte[] dst)        //读取当前Buffer的数据到dst中,并恰当地移动position位置

public byte get(int index);        //读取给定index索引上的数据,不改变postion位置 。

public ByteBuffer put(byte b)            //当前位置写入给定的数据,postion位置向后移一位

public ByteBuffer put(int index,byte b)        //将数据b写入当前Buffer的index位置。

public final ByteBuffer put(byte[] src)        //将给定的数据写入当前Buffer.

4、标志缓冲区

标志(mark)缓冲区是一项在数据和凸显时很有用的功能,它就像书签一样,在数据处理的过程中,可以随时记录当前位置。然后在任意时刻,回到这个位置,从而加快或简化数据处理流程。

mark()用于记录当前位置,reset函数用于恢复到mark所在的位置。下面这段代码就充分了解释了这两个函数

import java.nio.ByteBuffer;

public class BufferTest {

    public static void main(String[] args) {

        //从堆中分配
        ByteBuffer b = ByteBuffer.allocate(15);
        //从既有的数组中创建
//        byte array[] = new byte[1024];
//        ByteBuffer buffer = ByteBuffer.wrap(array);
        for(int i = 0 ;i<10;i++){
            b.put((byte)i);
        }
        b.flip(); //准备读取数据
        for (int i = 0; i < b.limit(); i++) {
            System.out.print(b.get());
            if(i==4){
                b.mark();   //在第4个位置做mark
                System.out.print("( mark at "+i+"  )");
            }
        }
        b.reset();        //回到mark的位置,并处理后续数据
        System.out.println("\nreset to mark");
        while(b.hasRemaining()){        //后续所有数据都将处理
            System.out.print(b.get());
        }
    }
}

以下图是输出结果:

5、复制缓冲区

public ByteBuffer duplicate()

这个函数对处理复杂的Buffer数据很有好处。因此新生在怕缓冲区和原缓冲共享相同的内存数据,并且,对任意一方的数据改动都是相互可见的,但是两者又独立维护了各自的postion,limit 和mark。这就大大增加了程序的灵活性。

6、缓冲区分片

缓冲区分片使用slice()方法实现,它将在现有的缓冲区中,创建新的子缓冲区,子缓冲区和父缓冲区共享数据。这个方法有助于将系统模块化。

  import java.nio.ByteBuffer;

public class BufferTest {

    public static void main(String[] args) {

        //从堆中分配
        ByteBuffer b = ByteBuffer.allocate(15);
        //从既有的数组中创建
//        byte array[] = new byte[1024];
//        ByteBuffer buffer = ByteBuffer.wrap(array);
        for(int i = 0 ;i<10;i++){
            b.put((byte)i);
        }
        b.position(2);    //当前位置为2
        b.limit(6);            //设置上限为6
        ByteBuffer subBuffer = b.slice(); //生成子缓冲区

        for (int i = 0; i < subBuffer.capacity(); i++) {
            byte bb = subBuffer.get(i);
            bb*=10;
            subBuffer.put(i,bb);
        }
        b.position(0);
        b.limit(b.capacity());
        while (b.hasRemaining()) {
            System.out.print(b.get()+",");
        }
    }
}

7、只读缓冲区

可以使用缓冲区对象的asReadOnlyBuffer()方法得到一个与当前缓冲区一致的,并且共享内存数据的只读缓冲区。只读缓冲区对于数据安全非常有用。当缓冲区作为参数传递给对象的某个方法时,由于无法确认该方法是否会破坏缓冲区数据,此时,使用只读缓冲区可以保证数据不被修改。同时,因为只读缓冲区和原始缓冲区是共享内存块的,因此,对原始缓冲区的修改,只读缓冲区也是可见的。

import java.nio.ByteBuffer;

public class BufferTest {

    public static void main(String[] args) {

        //从堆中分配
        ByteBuffer b = ByteBuffer.allocate(15);
        //从既有的数组中创建
//        byte array[] = new byte[1024];
//        ByteBuffer buffer = ByteBuffer.wrap(array);
        for(int i = 0 ;i<10;i++){
            b.put((byte)i);
        }
        ByteBuffer readOnly = b.asReadOnlyBuffer();  //创建只读缓冲区
        readOnly.flip();
        while (readOnly.hasRemaining()) {
            System.out.print(readOnly.get()+"  ");
        }
        System.out.println();
        b.put(2,(byte)20);    //修改了原始缓冲区的数据
        readOnly.flip();
        while (readOnly.hasRemaining()) {
            System.out.print(readOnly.get()+"  ");  //新的改动,在只读缓冲内可见
        }
    }
}

这里写图片描述" title="">

时间: 2024-10-11 01:52:08

NIO的Buffer的相关操作的相关文章

《Java源码分析》:Java NIO 之 Buffer

<Java源码分析>:Java NIO 之 Buffer 在上篇博文中,我们介绍了Java NIO 中Channel 和Buffer的基本使用方法,这篇博文将从源码的角度来看下Buffer的内部实现. 在Java API文档中,对Buffer的说明摘入如下: Buffer:是一个用于特定基本数据类型的容器.这里的特定基本数据类型指的是:除boolean类型的其他基本上数据类型. 缓冲区是特定基本数据类型元素的线性有限序列.除内容外,缓冲区饿基本属性还包括三个重要的属性,如下: 1.capaci

(二十四)linux新定时器:timefd及相关操作函数

timerfd是Linux为用户程序提供的一个定时器接口.这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景. 一,相关操作函数 #include <sys/timerfd.h> int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itim

Scala学习(三)----数组相关操作

数组相关操作 摘要: 本篇主要学习如何在Scala中操作数组.Java和C++程序员通常会选用数组或近似的结构(比如数组列表或向量)来收集一组元素.在Scala中,我们的选择更多,不过现在我们先假定不关心其他选择,而只是想马上开始用数组.本篇的要点包括: 1. 若长度固定则使用Array,若长度可能有变化则使用ArrayBuffer 2. 提供初始值时不要使用new 3. 用()来访问元素 4. 用for (elem<-arr)来遍历元素 5. 用for (elem<-arr if…)…yie

Scala详解---------数组相关操作

Scala中提供了一种数据结构-数组,其中存储相同类型的元素的固定大小的连续集合.数组用于存储数据的集合,但它往往是更加有用认为数组作为相同类型的变量的集合. 取替声明单个变量,如number0, number1, ..., 和number99,声明一个数组变量,如号码和使用numbers[0],numbers[1],...,numbers[99]表示单个变量.本教程介绍了如何声明数组变量,创建数组和使用索引的过程变量数组.数组的第一个元素的索引是数字0和最后一个元素的索引为元素的总数减去1.

NIO的Buffer类族和Channel

在NIO的实现中,Buffer是一个抽象类.JDK为每一种Java原生类型都创建了一个Buffer,如图所示. 除了ByteBuffer外,其他每一种Buffer都具有完全一样的操作,唯一的区别仅仅在于它们所对应的数据类型.因为ByteBuffer多用于绝大多数标准I/O操作的接口,因此它有些特殊的方法. 在NIO中和Buffer配合使用的还有Channel.Channel是一个双向通道,既可读,也可写.有点类似Stream,但Stream是单向的.应用程序中不能直接对Channel进行读写操作

Java NIO:Buffer、Channel 和 Selector

Buffer 一个 Buffer 本质上是内存中的一块,我们可以将数据写入这块内存,之后从这块内存获取数据. java.nio 定义了以下几个 Buffer 的实现,这个图读者应该也在不少地方见过了吧. 其实核心是最后的 ByteBuffer,前面的一大串类只是包装了一下它而已,我们使用最多的通常也是 ByteBuffer. 我们应该将 Buffer 理解为一个数组,IntBuffer.CharBuffer.DoubleBuffer 等分别对应 int[].char[].double[] 等.

从零学scala(二)数组相关操作、映射和元组

一:数组相关操作 定长数组 val array = Array[String]("a","b","c") //直接初始化数组的内容        println(array.mkString("|")) val array = new Array[String](2) //new一个长度为2的数据在通过更新的方法进行赋值        array.update(0, "0")        array.up

二叉树的相关操作

#include<stdio.h> #include<malloc.h> #define MAXSIZE 20 typedef char TEelemtype; typedef struct BiTNode{ TEelemtype data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; //队列的方式 typedef struct queueelem { BiTNode* b[MAXSIZE]; int front,rear;

二叉树各种相关操作(建立二叉树、前序、中序、后序、求二叉树的深度、查找二叉树节点,层次遍历二叉树等)(C语言版)

将二叉树相关的操作集中在一个实例里,有助于理解有关二叉树的相关操作: 1.定义树的结构体: 1 typedef struct TreeNode{ 2 int data; 3 struct TreeNode *left; 4 struct TreeNode *right; 5 }TreeNode; 2.创建根节点: 1 TreeNode *creatRoot(){ 2 TreeNode * root =(TreeNode *)malloc(sizeof(TreeNode)); 3 if(NULL=