我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Java NIO中Buffer缓冲区有什么用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Java NIO中Buffer缓冲区有什么用

这篇文章主要介绍Java NIO中Buffer缓冲区有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一、Buffer 简介

Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是通道读取到缓冲区

Java NIO中Buffer缓冲区有什么用

缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装 NIO Buffer 对象,并且提供了一组方法,用来方便的访问这块内存。缓冲区世纪上一个容器对象,更直接的说,其实就是一个数组,在 NIO 库中,所有数据都是用缓冲区处理的。 在读取数据时,它直接读到缓冲区中;在写数据时,它也是写入到缓冲区中的;任何时候访问 NIO 中的数据,都是将它放到缓冲区中。而在面向流 I/O 系统中,所有数据都是直接写入或者直接将数据读取到 Stream 对象中。

在 NIO 中,所有的缓冲区类型都是继承于抽象类 Buffer, 最常用的就是 ByteBuffer. 对于 Java 中国呢的基本类型,金额都有一个具体 Buffer 类型与之对应,他们之间的继承关系如下图所示:

Java NIO中Buffer缓冲区有什么用

二、Buffer 的基本方法

1、使用 Buffer 读写数据

使用 Buffer 读写数据,一般遵循以下四个步骤:

(1)写数据到 Buffer

(2)调用flip() 方法

(3)从 Buffer 中读取数据

(4)调用 clear() 方法或者 compact() 方法

当向 buffer 写数据时,buffer 会记录下写了多少数据。一旦要读数据,需要通过 flip() 方法将 buffer 从写模式切换到读模式。在读模式下,可以读取到之前写入到 buffer 的所有数据。一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用 clear() 或者 compact() 方法。clear() 方法会清空整个缓冲区。compact() 方法只会清除已经度过的数据。任何未读取的数据都被移动到了缓冲区的起始处,新写的数据将放到缓冲区未读数据的后面。

2、使用 Buffer 的例子

@Testpublic void buffer01() throws IOException {    // FileChannel    String pathName = "/Users/zhengsh/sourcecode.io/zhengsh-vvip/nio/class="lazy" data-src/main/resources/01.txt";    RandomAccessFile accessFile =        new RandomAccessFile(pathName, "rw");    FileChannel channel = accessFile.getChannel();    // 创建 buffer , 大小    ByteBuffer buffer = ByteBuffer.allocate(1024);    // 读    int bytesRead = channel.read(buffer);    while (bytesRead != -1) {        // read 模式        buffer.flip();        while (buffer.hasRemaining()) {            System.out.println((char) buffer.get());        }        buffer.clear();        channel.read(buffer);    }    accessFile.close();}@Testpublic void buffer02() {    // 创建 buffer    IntBuffer buffer = IntBuffer.allocate(8);    for (int i = 0; i < buffer.capacity(); i++) {        int j = 2 * (i + 1);        buffer.put(j);    }    // 重置缓冲区    buffer.flip();    while (buffer.hasRemaining()) {        int value = buffer.get();        System.out.println(value + "  ");    }}

三、Buffer 的 capactity、posittion 和limit

为了理解 Buffer 的工作原理,需要熟悉它的三个属性:

  • capacity

  • ponstition

  • limit

position limit 的含义取决于 Buffer 处在读模式还是写模式。不管 buffer 处于什么模式,capactity 的含义总是一样的。

这里有一个关于 capacity, postition 和 limit 在读模式中的说明:

(1) capactiy

作为一个内存块,Buffer 有一个固定的大小值,也叫做 “capactiy” . 你只能往里面写 capacity 个 byte

long、 char等类型。一旦 buffer 满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。

Java NIO中Buffer缓冲区有什么用

(2) postition

1)写数据到 Bufer 中时,position 表示写入数据的当前位置,position 的初始值为 0 。当一个 byte,long,等数据写入到 buffer 后,position 会向下移动到下一个可插入的元素的 buffer 但愿。position 最大可为 capacity -1 (因为 position 的初始值为 0)

2)读数据到 Buffer 中时,position 表示读数据的当前位置,如 position = 2 时表示已经开始读了 3 个 byte, 或者从第三个 byte 开始读取,通过 ByteBuffer.flip() 切换到读模式 position 会被重置为 0, 当 Buffer 从 position 读入数据后,position 会下移到下一个可读入的数据 Buffer 单元。

(3) limit

1)写数据时, limit 表示可以对 Buffer 最多写入多少个数据。写模式下,limit 等于 Buffer 的 capactiy

2)读数据时, limit 表示 Buffer 里有多少可读数据(not null 的数据),因此能读取到之前写入的所有数据(limit 被设置为已写数据的数量,这个值在写模式下就是 position)

四、Buffer 的类型

Java NIO 有一下 Buffer 的类型

  • ByteBuffer

  • MappedByteBuffer

  • CharBuffer

  • DoubleBuffer

  • FloatBuffer

  • LongBuffer

  • ShortBuffer

这些 buffer 类型都代表了不同的数据类型。换句话说,就是可以通过 char ,short, int, long , float 或者 double 类型来操作缓冲区的字节。

五、Buffer 分配和写数据

1、 Buffer 分配

想要获取一个 Buffer 对象首先要进行分配。每一个 Buffer 类都有一个 allocate 方法。

下面是一个分配 48 字节 capactiy 的 ByteBuffer 的例子。

ByteBuffer buf = ByteBuffer.alloacte(48);

这是分配一个可存储 1024 个字符的 CharBuffer:

ByteBuffer buf = ByteBuffer.alloacte(1024);

2、向 buffer 中写数据

写数据到 Buffer 有两种方式:

  • (1)从 channel 写到 Buffer

  • (2)通过 Buffer 的 put 方法写到 Buffer 里。

从 Channel 写到 Buffer 的例子

int byteRead = channel.read(buf); // read into buffer

通过 put 方法写入 buffer 的例子:

buf.put(100);

put 的方法有很多版本,允许你不同的方式把数据写入到 buffer 中,例如,写到一个指定的位置,或者把字节数组写入到 Buffer .

3、flip() 方法

flip 方法将 Buffer 从写模式切换到读模式。调用 flip() 方法将会 position 设置为 0 , 并且将 limt 设置为之前 position 的值。换句话说,position 现在用于标记读的位置,limit 表示之前写进了多少个 byte, char 等(现在能读取多少个 byte, char 等)。

六、从 Buffer 中读取数据

从 Buffer 中读取数据到 Channel 中:

(1) 从 Buffer 中读取数据到 Channel

(2)使用 get 方法从 Buffer 中读取数据

从 Buffer 中读取数据到 Channnel 到例子:

// read form buffer into channel int bytesWritten = inChannel.write(buf);

使用 get() 方法从 Buffer 中读取数据的例子:

byte aByte = buf.get();

get 方法中有很多版本,允许你以不同的方式 Buffer 中读取数据。例如,从指定 position 读取,或者从 Buffer 中读取到字节数组。

七、Buffer 几个方法

1、rewind() 方法

Buffer.rewind() 将 position 返回0, 所以你可以重读 Buffer 中的所有数据。limit 保持不变,仍然表示能从 Buffer 中读取到多少个元素(byte, char 等)。

2、clear() 与 compact() 方法

一旦读完 Buffer 中的数据,需要让 Buffer 准备好再次被写入。可以通过 clear() 或 compact() 方法来完成

如果调用的是 cleanr () 方法,position 兼备设置为 0 , limit 被设置成 capactiy 的值。换句话说,Buffer 被清空了。 Buffer 中的数据并未清除,只是这些标记高数我们从哪里开始往 Buffer 中写数据。

如果 Buffer 中有些数未读的数据,调用 clear() 方法,数据将 “被遗忘”,意味着不在有任何标记会告诉你那些数据被读过,那些还没有。

如果 Buffer 中依然有未读的数据,且后续还需要这些数据,但是此时想要先写这些数据,那么使用 compact() 方法。

compact() 方法将所有未读的数据拷贝到 Buffer 起始处。然后将 position 设置到最后一个未读元素正后面。 limit 属性依然像 clear() 方法一样。设置成 capacity. 现在 Buffer 准备好写数据了,但是不会覆盖未读的数据。

3、mark() 与 reset() 方法

通过调用 Buffer.mark() 方法,可以标记 Buffer 中的一个特定 position . 之后可以通过调用 Buffer.reset() 方法恢复到这个 position 例如:

buffer.mark();// call buffer.get() a couple of times, e.g. during parsing  buffer.reset(); // set position back to mark

八、缓冲区操作

1、缓冲区分片

在 NIO 中除了可以分配或者包装一个缓冲区对象外,还可以更具现有的缓冲区对象来创建一个子缓冲区,即现有缓冲区上切出一片来作为一个新的缓冲区,但现有的缓冲区与创建的子缓冲区在底层数组层面上是数据共享的,也就是说,子缓冲区相当于是现有缓冲区的一个视图窗口。调用 slice() 方法可以创建一个子缓冲区。

// 缓冲区分片@Testpublic void b01() {    ByteBuffer buffer = ByteBuffer.allocate(10);    // 放入数据    for (int i = 0; i < buffer.capacity(); i++) {        buffer.put((byte) i);    }    // 创建子缓冲区    buffer.position(3);    buffer.limit(7);    ByteBuffer slice = buffer.slice();    // 改变子缓冲区中的内容    for (int i = 0; i < slice.capacity(); i++) {        byte b = slice.get(i);        b *= 10;        slice.put(i, b);    }    // 复位    buffer.position(0);    buffer.limit(buffer.capacity());    while (buffer.remaining() > 0) {        System.out.println(buffer.get());    }}

输出结果如下:

Java NIO中Buffer缓冲区有什么用

2、只读缓冲区

只读缓冲区非常简单,可以读取他们,但是不能向他们写入数据。可以通过调用缓冲区的 asReadOnlyBufer() 方法,将任何常规缓冲区转换为只读缓冲区,这个方法返回一个与原缓冲区完全相同的缓冲区,并与原缓冲区共享数据,只不过它是只读的。如果原缓冲区的内容发生了变化,只读缓冲区的内容随之发生变化:

// 只读缓冲区@Testpublic void b02() {    ByteBuffer buffer = ByteBuffer.allocate(10);    // 放入数据    for (int i = 0; i < buffer.capacity(); i++) {        buffer.put((byte) i);    }    // 创建一个只读缓冲区    ByteBuffer readOnlyBuf = buffer.asReadOnlyBuffer();    for (int i = 0; i < buffer.capacity(); i++) {        byte b = buffer.get(i);        b *= 10;        buffer.put(i, b);    }    readOnlyBuf.position(0);    readOnlyBuf.limit(readOnlyBuf.capacity());    while (readOnlyBuf.remaining() > 0) {        System.out.println(readOnlyBuf.get());    }}

3、直接缓冲区

直接缓冲区为了加快 I/O 速度,使用一种特殊的方式为其分配内存的缓冲区, JDK 文档的描述为:给定一个直接字节缓冲区,Java 虚拟机将尽最大努力直接对它执行本机 I/O 操作之前(或之后),尝试避免将缓冲区的内容拷贝到一个中间缓冲区中或者从一个中间缓冲区中拷贝数据。要分配直接缓冲区,需要调 allocatieDirect() 方法,而不是 alloacte() 方法,使用方式与普通缓冲区并无区别。

// 直接缓冲区,文件拷贝@Testpublic void b03() throws IOException {    String filePath = "/xx/01.txt";    FileInputStream inputStream = new FileInputStream(filePath);    FileChannel fileInChannel = inputStream.getChannel();    String outPath = "/xx/02.txt";    FileOutputStream outputStream = new FileOutputStream(outPath);    FileChannel fileOutChannel1 = outputStream.getChannel();    //  使用 allocateDirect , 而不是 allocate    ByteBuffer buffer = ByteBuffer.allocateDirect(1024);    while (true) {        buffer.clear();        int r = fileInChannel.read(buffer);        if (r == -1) {            break;        }        buffer.flip();        fileOutChannel1.write(buffer);    }    fileInChannel.close();    fileOutChannel1.close();}

4、内存映射文件 I/O

内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者通道的 I/O 快得多。内存映射 I/O 是通过使文件中的数据出现为内存数组的内容来完成的,这起初听起来师傅不过就是为了将整个文件读取到内容中,但是事实上并不是这样的。一般来说只有文件实际读取或者写入的部分才会映射到内存中。

// 内存映射文件 I/O @Testpublic void b04() throws IOException {    String filePath = "/xxx/01.txt";    RandomAccessFile randomAccessFile = new RandomAccessFile(filePath, "rw");    FileChannel fileChannel = randomAccessFile.getChannel();    MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, 1024);    mappedByteBuffer.put(0, (byte) 97);    mappedByteBuffer.put(1023, (byte) 122);    fileChannel.close();}

以上是“Java NIO中Buffer缓冲区有什么用”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网行业资讯频道!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Java NIO中Buffer缓冲区有什么用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java NIO中Buffer缓冲区有什么用

这篇文章主要介绍Java NIO中Buffer缓冲区有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、Buffer 简介Java NIO 中的 Buffer 用于和 NIO 通道进行交互。数据是通道读取到缓冲
2023-06-29

Java NIO直接缓冲区和非直接缓冲区是什么

这篇文章主要讲解了“Java NIO直接缓冲区和非直接缓冲区是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java NIO直接缓冲区和非直接缓冲区是什么”吧!定义java nio字节缓
2023-06-21

java中NIO通道和缓冲区是如何工作的

这篇文章将为大家详细讲解有关java中NIO通道和缓冲区是如何工作的,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。通道 和 缓冲区 是 NIO 中的核心对象,几乎在每一个 I/O 操作中都要使用它们。通道
2023-06-17

java中io和nio有什么区别

java中io和nio有什么区别?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。Java有哪些集合类Java中的集合主要分为四类:1、List列表:有序的,可重复的;2、Queu
2023-06-14

MySQL中读页缓冲区buffer pool的知识点有哪些

这篇“MySQL中读页缓冲区buffer pool的知识点有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“MySQL中读
2023-06-30

python中什么是缓冲区

这篇文章将为大家详细讲解有关python中什么是缓冲区,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Python的优点有哪些1、简单易用,与C/C++、Java、C# 等传统语言相比,Pyt
2023-06-14

java中字符流缓冲区的作用是什么

本篇文章为大家展示了java中字符流缓冲区的作用是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1. 为什么要缓冲区?程序频繁地操作一个资源(如文件),则性能会很低,此时为了提升性能,就可以将一
2023-05-31

Java中的Netty缓冲区的用法

这篇文章主要介绍“Java中的Netty缓冲区的用法”,在日常操作中,相信很多人在Java中的Netty缓冲区的用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的Netty缓冲区的用法”的疑惑有所
2023-06-16

java中BIO、NIO、AIO三者有什么区别

这篇文章给大家介绍java中BIO、NIO、AIO三者有什么区别,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、BIO(Blocking IO,也被称作old IO)同步阻塞模型,一个客户端连接对应一个处理线程对于每
2023-06-14

Java中BIO、NIO和AIO的区别是什么

这篇文章主要讲解了“Java中BIO、NIO和AIO的区别是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java中BIO、NIO和AIO的区别是什么”吧!IO什么是IO? 它是指计算机
2023-06-22

Linux中内存buffer和cache有什么区别

小编给大家分享一下Linux中内存buffer和cache有什么区别,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!细心的朋友会注意到,当你在linux下频繁存取文
2023-06-13

go_package 选项在协议缓冲区文件中的作用是什么?

大家好,今天本人给大家带来文章《go_package 选项在协议缓冲区文件中的作用是什么?》,文中内容主要涉及到,如果你对Golang方面的知识点感兴趣,那就请各位朋友继续看下去吧~希望能真正帮到你们,谢谢!问题内容我做了一些研究,包括查看
go_package 选项在协议缓冲区文件中的作用是什么?
2024-04-05

日志记录器缓冲区大小的作用是什么

本篇内容主要讲解“日志记录器缓冲区大小的作用是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“日志记录器缓冲区大小的作用是什么”吧!日志记录器缓冲区大小日志的作用是:主要是用于给工程师们反馈使
2023-06-20

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录