mappedbytebuffer_Java NIO Buffer【MappedByteBuffer】概述与FileChannel的联系

 NIO【Non-blocking IO非阻塞式IO】,可以让你非阻塞的使用IO,例如:当线程从通道读取数据到缓冲区时,线程还是可以进行其他事情。当数据被写入到缓冲区时,线程可以继续处理它。从缓冲区写入通道也类似,主要分为3部分:Channels and Buffers and Selectors(通道和缓冲区和选择器)今天我们要讲的就是Buffer概述

听歌时间

01

Buffer概述

/**
 * Java NIO中的Buffer用于和NIO通道{Channel【FileChannel|SocketChannel】}进行交互,
 * 数据是从通道读入缓冲区,从缓冲区写入到通道中的。
 * 缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。
 * 这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。
 * 用于特定基本类型的数据的缓冲区容器,每个非布尔基本类型都有这个类的一个子类
 * ByteBuffer , CharBuffer , DoubleBuffer , FloatBuffer , IntBuffer , LongBuffer , ShortBuffer
 * 其中和ByteBuffer相关的子类有3个:
 * MappedByteBuffer,HeapByteBuffer,DirectByteBuffer extends MappedByteBuffer
 * 是特定原始类型的元素的线性有限序列缓冲区。除了其内容【缓冲区数组】,
 * 缓冲区对象还有其它3个基本属性
 * 1:capacity:它所包含的元素数量叫缓冲区的容量。缓冲区的容量永远不会为负且永远不会改变
 * 2:limit:第一个不能被读/写的元素的索引叫缓冲区的限制。缓冲区的限制永远不大于缓冲区的容量
 * 3:position:下一个要读取或写入的元素的索引叫缓冲区的位置。缓冲区的位置永远不会大于其限制。
 * Buffer类的每个子类定义了一系列get和put操作:
 * 相对的读写操作每次都从当前位置开始读写,并将位置+1
 * 绝对的读写操作采用显式的元素索引,并不影响位置
 * 无论是相对的还是绝对的读写操作,索引都不能超过【exceeds】其限制
 * 标记,位置,极限和容量值满足以下关系:
 * 0 <= mark <= position <= limit <= capacity
 * 标记和重置、清理,翻转和倒带
 * 调用reset方法一定保证mark方法被调用过
 * mark方法源码:
 * mark = position;return this;
 * reset方法源码:
 * int m = mark;if (m < 0){throw new InvalidMarkException()};position = m;return this;
 * clear方法源码:
 * position = 0;limit = capacity;mark = -1;return this;
 * flip方法源码:
 * limit = position;position = 0;mark = -1;return this;
 * rewind方法源码:
 * position = 0;mark = -1;return this;
 * 读与写操作之间要调用flip方法
 * 线程不安全,可以链式调用
 * b.flip().position(23).limit(42);
 *
 */

02

代码演示

import java.nio.ByteBuffer;import java.util.Arrays;public class ByteBufferTest {public static void main(String[] args) {//根据指定的容量创建一个字节缓冲区,两种方式//分配5个字节
        ByteBuffer byteBuffer = ByteBuffer.allocate(5);//ByteBuffer.wrap(new byte[5]);// 往 ByteBuffer放入数值
        byteBuffer.put((byte)10);
        byteBuffer.put((byte)20);//byteBuffer.putInt(1000);//放入一个int占4个字节
        System.out.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));
        System.out.printf("打印一下是否有字节数组: %s%n",byteBuffer.hasArray());
        System.out.printf("打印一下指针位置: %s%n",byteBuffer.position());
        System.out.printf("打印一下字节缓冲区容量: %s%n",byteBuffer.capacity());
        System.out.printf("打印一下字节缓冲区限制: %s%n",byteBuffer.limit());
        System.out.printf("打印一下字节缓冲区从当前位置到限制之间的剩余元素: %s%n",byteBuffer.remaining());
        System.out.printf("从当前位置到限制之间是否有剩余元素: %s%n",byteBuffer.hasRemaining());
        System.out.printf("是否是直接缓冲区: %s%n",byteBuffer.isDirect());
        System.out.printf("该缓冲区是否是只读: %s%n",byteBuffer.isReadOnly());//设置位置和限制
        byteBuffer.flip().position(2).limit(4);
        System.out.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));//get方法获取的是position+1的索引对应的值
        System.out.printf("flip之后获取位置为2的数据: %s%n",byteBuffer.get());
        System.out.printf("标记后重置: %s%n",byteBuffer.mark().reset());
        byteBuffer.put((byte)60);
        System.out.printf("重新获取位置: %s%n",byteBuffer.position());//该方法和flip方法差不多,都用于读写切换,只不过rewind方法前提是limit被合理的设置
        byteBuffer.rewind();
        System.out.printf("重新获取值: %s%n",byteBuffer.get());//重置为最开始创建的时候,只不过没有清除数据
        System.out.printf("重置但不清除数据: %s%n",byteBuffer.clear());//创建一个新的剩余内容子共享缓冲区,【也就是说字节数组是共享的】// 该新的缓冲区是指定缓冲区的剩余部分,修改哪一个另外一个都会同步修改//这两个缓冲区的位置,限制和标记值将是独立的//通过position++加上offset来定位在原数组中的位置
        ByteBuffer subByteBuffer = byteBuffer.slice();
        subByteBuffer.put((byte)30);
        System.out.printf("打印一下子字节数组: %s%n",Arrays.toString(subByteBuffer.array()));//只有调用slice方法,offset才会被设置
        System.out.printf("打印一下缓冲区偏移量: %s%n",subByteBuffer.arrayOffset());
        System.out.printf("打印一下子指针位置: %s%n",subByteBuffer.position());
        System.out.printf("打印一下子字节缓冲区容量: %s%n",subByteBuffer.capacity());
        System.err.printf("打印一下字节数组: %s%n",Arrays.toString(byteBuffer.array()));
        System.err.printf("打印一下指针位置: %s%n",byteBuffer.position());
        System.err.printf("打印一下字节缓冲区容量: %s%n",byteBuffer.capacity());
        System.err.printf("打印一下字节缓冲区限制: %s%n",byteBuffer.limit());
        byteBuffer.rewind();
        System.err.printf("获取: %s%n",byteBuffer.get());
    }
}

03

MappedByteBuffer概述与联系

直接字节缓冲器,其内容是文件的存储器映射区域。
映射的字节缓冲区是通过FileChannel.map方法创建的。此类扩展了具有特定于内存映射文件区域的操作的ByteBuffer类。

映射字节缓冲区及其表示的文件映射在缓冲区本身被垃圾回收之前保持有效。

映射字节缓冲区的内容可以随时更改,例如,如果该程序或其他映射文件的对应区域的内容被更改。
这种变化是否发生,何时发生,是操作系统依赖的,因此是未指定的。

映射字节缓冲区的全部或部分可能在任何时候变得无法访问,例如映射文件被截断。
访问映射字节缓冲区的不可访问区域的尝试不会更改缓冲区的内容,
并将导致在访问时或稍后的时候抛出未指定的异常。因此,强烈建议您采取适当的预防措施,
以避免该程序或同时运行的程序对映射文件进行操作,但读取或写入文件的内容除外。

映射的字节缓冲区的行为与普通的直接字节缓冲区不同。

04

FileChannel

d0ba552a2e9b4f930f19cd6c6d4dc201.png

6d199dfb9fd3058ad48d540ae7a40c1a.gif

写在最后

总结:今天花了点时间写了关于Buffer的概述,关于实战部分请参考往期精彩文章

>>>往期精彩文章

使用一种全新的方式【java NIO】拆分大电影文件,并合并分割后的文
件为电影文件

如果喜欢,欢迎点赞分享给你身边要的人!

我欲寻花问路,直入白云深处。

0cf003728cd5f860d0e6d93790ef7971.gif

156c5dbe55a2cda86af6d19fb78e0a16.gif

62a85eb7500b2a35dfce5cbc3f11fae3.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一个示例代码,将Java的FileChannelMappedByteBuffer用于读写文件,并将读和写的代码分开。请参考以下示例: 首先,我们来看一下读取文件的代码: ```java import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class FileReader { public static void main(String[] args) { try { // 打开文件 RandomAccessFile file = new RandomAccessFile("input.txt", "r"); FileChannel channel = file.getChannel(); // 将文件映射到内存中 MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); // 读取文件内容 while (buffer.hasRemaining()) { System.out.print((char) buffer.get()); } // 关闭文件 channel.close(); file.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 接下来,我们来看一下写入文件的代码: ```java import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class FileWriter { public static void main(String[] args) { try { // 打开文件 RandomAccessFile file = new RandomAccessFile("output.txt", "rw"); FileChannel channel = file.getChannel(); // 将文件映射到内存中 MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 1024); // 写入数据到缓冲区 String data = "Hello, World!"; buffer.put(data.getBytes()); // 刷新缓冲区到文件 buffer.force(); // 关闭文件 channel.close(); file.close(); } catch (Exception e) { e.printStackTrace(); } } } ``` 这两个示例代码分别用于读取和写入文件。您可以根据自己的需求进行修改和扩展。记得替换文件名和路径以适应您的实际情况。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值