缓冲区是什么数据结构_数据的存储结构有哪些[通俗易懂]

缓冲区是什么数据结构_数据的存储结构有哪些[通俗易懂]一点睛NIO,可以称为NewIO或NonBlockingIO,是在JDK1.4后提供的新API

一 点睛

NIO,可以称为 New IO 或 Non Blocking IO,是在 JDK 1.4 后提供的新 API。传统的I/O 是阻塞式的 I/O、面向流的操作;而 NIO 是非阻塞 I/O 、面向通道(Channel) 和 缓冲区(Buffer) 的操作。此外,NIO 还提供了选择器(Selector)全新的概念,这些都使 NIO 在传输数据时更加高效。下图为选择器、通道和缓冲区的关系图。

缓冲区是什么数据结构_数据的存储结构有哪些[通俗易懂]

二 NIO 数据存储结构——缓冲区 Buffer

Buffer 的底层是一个数组,用于存储数据。NIO 提供了 7 种类型的缓冲区,用于存储不同类型的数据:ByteBuffer、IntBuffer、ShortBuffer、LongBuffer、FloatBuffer、DoubleBuffer、CharBuffer,并且它们都继承自 java.nio.Buffer。

在 Buffer 类中有 5 个重要的属性。

1 int position:下一个将要被读或写的元素位置。

2 int limit:限制 Buffer 中能够存放的元素个数,换句话说,limit 及之后的位置不能使用。

3 int capacity:Buffer 的最大容量,并且在创建后不能更改。

4 int mark:标记,可以在 Buffer 设置一个标记,之后可以通过 reset() 方法返回到列表该标记的位置。

5 long address:堆外内存的地址。

三 缓存区的常用方法

以 ByteBuffer 为例进行说明

方法

简介

public static ByteBuffer allocate(int capacity)

分配大小为 capacity 的非直接缓冲区(单位byte)

public static ByteBuffer allocateDirect(int capacity)

分配大小为 capacity 的直接缓冲区(单位byte)

public abstract ByteBuffer put(byte b)  

public abstract ByteBuffer put(int index, byte b)

public final ByteBuffer put(byte[] src)

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

向缓冲区中存放数据

public abstract byte get()

public abstract byte get(int index)

public ByteBuffer get(byte[] dst)

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

从缓存区中读取数据

public abstract ByteBuffer asReadOnlyBuffer()

将一个 Buffer 转为一个只读 Buffer。之后,不能再对转换后的 Buffer 进行写操作

public abstract ByteBuffer slice()

将原 Buffer 从 position 到 limit 之间的部分数据交给一个新的 Buffer 引用。也就是说,此方法返回的 Buffer 引用的数据,是原 Buffer 的一个子集。并且,新的 Buffer 引用和原 Buffer 引用共享相同的数据。

public static ByteBuffer wrap(byte[] array)

返回一个内容为 array 的 Buffer。此外,如果修改缓冲区的内容,array 也会随着改变,反之亦然。

public final Buffer flip()

将写模式转换成读模式

public final Buffer rewind()

用于重复读,具体重现参考源码

public final Buffer clear()

清空 Buffer,具体重现参考源码

public final Buffer mark()

标记:mark = position,具体重现参考源码

public final Buffer reset()

重置:position = mark,具体重现参考源码

四 基本演示

1 代码

public class NIODemo {
    public static void test1() {
        ByteBuffer buffer = ByteBuffer.allocate(100);
        System.out.println("---allocate----");
        System.out.println("position:" + buffer.position());  // position:0
        System.out.println("limit:" + buffer.limit()); // limit:100
        System.out.println("capacity(定义之后,不会再改变):" + buffer.capacity()); // capacity(定义之后,不会再改变):100

        // 向Buffer中存放数据
        System.out.println("---put()----");
        buffer.put("helloworld".getBytes());  
        System.out.println("position:" + buffer.position()); // position:10
        System.out.println("limit:" + buffer.limit());  // limit:100

        // 切换到读模式
        System.out.println("---flip()----");
        buffer.flip();
        System.out.println("position:" + buffer.position()); // position:0
        System.out.println("limit:" + buffer.limit()); // limit:10

        // 从Buffer中读取数据
        System.out.println("---get()----");
        byte[] bs = new byte[buffer.limit()];
        buffer.get(bs); // 读取数据,同时会后移position
        System.out.println("读取到的数据:" + new String(bs)); // 读取到的数据:helloworld
        System.out.println("position:" + buffer.position()); // position:10
        System.out.println("limit:" + buffer.limit()); // limit:10

        System.out.println("----slice()---");
        buffer = ByteBuffer.allocate(8);
        // buffer:0,1,2,3,4,5,6,7
        for (int i = 0; i < buffer.capacity(); i++) {
            buffer.put((byte) i);
        }
        buffer.position(2);
        buffer.limit(6);
        // sliceBuffer:2,3,4,5;获取从 position 到 limit之间 buffer的引用。
        ByteBuffer sliceBuffer = buffer.slice();
        // sliceBuffer 与 原Buffer 共享相同的数据;即修改 sliceBuffer 中的数据时,buffer 也会改变。
        for (int i = 0; i < sliceBuffer.capacity(); i++) {
            byte b = sliceBuffer.get(i);
            b += 100;
            sliceBuffer.put(i, b);
        }

        // 测试
        System.out.println("当修改了 sliceBuffer 之后,查看 buffer:");
        buffer.position(0);
        buffer.limit(buffer.capacity());
        while (buffer.hasRemaining()) {//{x,x,x,x,x,x}  buffer.hasRemaining():判断是否有剩余元素
            System.out.print(buffer.get() + ","); // 0,1,102,103,104,105,6,7,
        }
        System.out.println();

        System.out.println("----mark--------");
        ByteBuffer buffer2 = ByteBuffer.allocate(100);
        buffer2.put("abcdefg".getBytes());

        // 在此时的 position 位置处,做一个标记 mark
        buffer2.mark();
        System.out.println("position:" + buffer2.position()); // position:7
        System.out.println("mark:" + buffer2.mark().position()); // mark:7

        /*
         通过get(byte[] dst, int offset, int length)方法,读取buffer中的“cde”。
         注意,此方法可以直接从 Buffer 中的指定位置 offset 开始读取数据,而不需要flip()或rewind()。
        */
        buffer2.get(bs, 2, 3);
        buffer2.reset(); // 恢复到 position 的位置 7
        System.out.println("position:" + buffer2.position()); // position:7
        System.out.println("mark:" + buffer2.mark().position()); // mark:7

        // 判断缓冲区是否有剩余数据
        if (buffer2.hasRemaining()) {
            System.out.println("Buffer中的剩余空间数:" + buffer2.remaining()); // Buffer中的剩余空间数:93
        }

        // 重复读rewind() : 1.postion=0,2.取消mark()
        System.out.println("---rewind()----"); 
        buffer2.rewind();
        System.out.println("position:" + buffer2.position()); // position:0

        // clear()"清空"缓冲区
        System.out.println("-------clear()--------");
        ByteBuffer buffer3 = ByteBuffer.allocate(100);
        buffer3.put("abc".getBytes());
        buffer3.clear(); // "清空"缓冲区 :position=0,但数据并没有真正被删除,只是处于废弃状态
        System.out.println("position:" + buffer3.position()); // position:0
        System.out.println("limit:" + buffer3.limit()); // limit:100
        System.out.println("clear()之后,仍然可以获取到Buffer中的数据:" + (char) buffer3.get(1)); // clear()之后,仍然可以获取到Buffer中的数据:b
    }
    public static void main(String[] args) throws IOException {
        test1();
    }
}

2 测试结果

—allocate—-

position:0

limit:100

capacity(定义之后,不会再改变):100

—put()—-

position:10

limit:100

—flip()—-

position:0

limit:10

—get()—-

读取到的数据:helloworld

position:10

limit:10

—-slice()—

当修改了sliceBuffer之后,查看buffer:

0,1,102,103,104,105,6,7,

—-mark——–

position:7

mark:7

position:7

mark:7

Buffer中的剩余空间数:93

—rewind()—-

position:0

——-clear()——–

position:0

limit:100

clear()之后,仍然可以获取到Buffer中的数据:b

五 Buffer 存储各类型数据

1 代码

package nio;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.Pipe;
import java.nio.charset.CharacterCodingException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class NIODemo {
    // Buffer 存储各类型数据
    public static void test() throws CharacterCodingException {
        ByteBuffer buffer = ByteBuffer.allocate(32);
        buffer.putDouble(3.14159);
        buffer.putChar('程');
        buffer.flip();
        // 必须保证 get 和 put 的顺序一致
        System.out.println(buffer.getDouble());
        System.out.println(buffer.getChar());
    }

    public static void main(String[] args) throws IOException {
        test();
    }
}

2 测试

3.14159

 

今天的文章缓冲区是什么数据结构_数据的存储结构有哪些[通俗易懂]分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/84914.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注