当前位置:首页 > 科技  > 软件

Java Nio FileChannel堆内堆外数据读写全流程分析及使用

来源: 责编: 时间:2024-05-27 08:57:11 293观看
导读背景java nio中文件读写不管是普通文件读写,还是基于mmap实现零拷贝,都离不开FileChannel这个类。随便打开RocketMQ 源码搜索FileChannel。就可以看到使用频率。图片kafka也是。图片所以在java中文件读写FileChannel尤

背景

java nio中文件读写不管是普通文件读写,还是基于mmap实现零拷贝,都离不开FileChannel这个类。cmV28资讯网——每日最新资讯28at.com

随便打开RocketMQ 源码搜索FileChannel。cmV28资讯网——每日最新资讯28at.com

就可以看到使用频率。cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

kafka也是。cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

所以在java中文件读写FileChannel尤为重用。cmV28资讯网——每日最新资讯28at.com

java文件读写全流程

图片图片cmV28资讯网——每日最新资讯28at.com

这里说的仅仅是FileChannel基于堆内存(HeapByteBuffer)的文件读写。cmV28资讯网——每日最新资讯28at.com

如果是mmap或者堆外内存,可能有些步骤会省略,相当于有一些优化。cmV28资讯网——每日最新资讯28at.com

  1. FileChannel调用read,将HeapByteBuffer拷贝到DirectByteBuffer。
  2. JVM在native层使用read系统调用进行文件读取, 这里需要进行上下文切换,从用户态进入内核态。
  3. JVM 进程进入虚拟文件系统层,查看文件数据再page cache是否缓存,如果有则直接从page cache读取并返回到DirectByteBuffer。
  4. 如果请求文件数据不在page caceh,则进入文件系统。通过块驱动设备进行真正的IO,并进行文件预读,比如读取的文件可能只有1-10,但是会将1-20都读取。
  5. 磁盘控制器DMA将磁盘中的数据拷贝到page cache中。这里发生了一次数据拷贝(非CPU拷贝)。
  6. CPU将page cache数据拷贝到DirectByteBuffer,因为page cache属于内核空间,JVM进程无法直接寻址。这里是发生第二次数据拷贝。
  7. JVM进程从内核态切换回用户态,这里如果使用的是堆内存(HeapByteBuffer),实际还需要将堆外内存DirectByteBuffer拷贝到堆内存(HeapByteBuffer)。

FileChannel读写文件(非MMAP)

public static void main(String[] args) {        String filename = "小奏技术.txt";        String content = "Hello, 小奏技术.";        // 写入文件        writeFile(filename, content);        // 读取文件        System.out.println("Reading from file:");        readFile(filename);    }    public static void writeFile(String filename, String content) {        // 创建文件对象        File file = new File(filename);        // 确保文件存在        if (!file.exists()) {            try {                boolean created = file.createNewFile();                if (!created) {                    System.err.println("Unable to create file: " + filename);                    return;                }            } catch (Exception e) {                System.err.println("An error occurred while creating the file: " + e.getMessage());                return;            }        }        // 使用FileChannel写入文件        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");             FileChannel fileChannel = randomAccessFile.getChannel()) {            ByteBuffer buffer = ByteBuffer.allocate(content.getBytes().length);            buffer.put(content.getBytes());            buffer.flip(); // 切换到读模式            while (buffer.hasRemaining()) {                fileChannel.write(buffer);            }        } catch (Exception e) {            System.err.println("An error occurred while writing to the file: " + e.getMessage());        }    }    public static void readFile(String filename) {        // 使用FileChannel读取文件        try (RandomAccessFile randomAccessFile = new RandomAccessFile(filename, "r");             FileChannel fileChannel = randomAccessFile.getChannel()) {            ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());            while (fileChannel.read(buffer) > 0) {                // Do nothing, just read            }            // 切换到读模式            buffer.flip();            /* while (buffer.hasRemaining()) {                System.out.print((char) buffer.get());            }*/            Charset charset = StandardCharsets.UTF_8;             String fileContent = charset.decode(buffer).toString();            System.out.print(fileContent);        } catch (Exception e) {            System.err.println("An error occurred while reading the file: " + e.getMessage());        }    }

这里需要注意的一个细节 我们分配的内存的方式是:cmV28资讯网——每日最新资讯28at.com

ByteBuffer.allocate()

这里我们可以进入看看源码:cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

实际构造的是HeapByteBuffer,也就是JVM的堆内存。cmV28资讯网——每日最新资讯28at.com

如果我们使用:cmV28资讯网——每日最新资讯28at.com

ByteBuffer.allocateDirect()

图片图片cmV28资讯网——每日最新资讯28at.com

则构造的是堆外内存DirectByteBuffer。cmV28资讯网——每日最新资讯28at.com

HeapByteBuffer和DirectByteBuffer文件读写区别

我们看看FileChannel read方法:cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

发现IO相关的处理被封装在IOUtil,我们继续看看IOUtil的write方法:cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

可以看到如果是DirectBuffer则可以直接写。如果是HeapByteBuffer则需要转换为DirectByteBuffer。cmV28资讯网——每日最新资讯28at.com

图片图片cmV28资讯网——每日最新资讯28at.com

为什么要在DirectByteBuffer做一层转换

主要是HeapByteBuffer受JVM管理,也就是会受到GC影响。如果在进行native调用的时候发生了GC,会导致HeapByteBuffer的内容出现错误。具体详细的说明可以看看这篇MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异。讲解的非常清晰。cmV28资讯网——每日最新资讯28at.com

参考

  • MappedByteBuffer VS FileChannel:从内核层面对比两者的性能差异 

本文链接:http://www.28at.com/showinfo-26-90858-0.htmlJava Nio FileChannel堆内堆外数据读写全流程分析及使用

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Wire:Go语言依赖注入的利器

下一篇: 避免锁表:为Update语句中的Where条件添加索引字段

标签:
  • 热门焦点
  • 一加Ace2 Pro真机揭晓 钛空灰配色质感拉满

    终于,在经过了几波预热之后,一加Ace2 Pro的外观真机图在网上出现了。还是博主数码闲聊站曝光的,这次的外观设计还是延续了一加11的方案,只是细节上有了调整,例如新加入了钛空灰
  • 5月iOS设备好评榜:iPhone 14仅排第43?

    来到新的一月,安兔兔的各个榜单又重新汇总了数据,像安卓阵营的榜单都有着比较大的变动,不过iOS由于设备的更新换代并没有那么快,所以相对来说变化并不大,特别是iOS好评榜,老款设
  • 之家push系统迭代之路

    前言在这个信息爆炸的互联网时代,能够及时准确获取信息是当今社会要解决的关键问题之一。随着之家用户体量和内容规模的不断增大,传统的靠"主动拉"获取信息的方式已不能满足用
  • .NET 程序的 GDI 句柄泄露的再反思

    一、背景1. 讲故事上个月我写过一篇 如何洞察 C# 程序的 GDI 句柄泄露 文章,当时用的是 GDIView + WinDbg 把问题搞定,前者用来定位泄露资源,后者用来定位泄露代码,后面有朋友反
  • 一文搞定Java NIO,以及各种奇葩流

    大家好,我是哪吒。很多朋友问我,如何才能学好IO流,对各种流的概念,云里雾里的,不求甚解。用到的时候,现百度,功能虽然实现了,但是为什么用这个?不知道。更别说效率问题了~下次再遇到,
  • iQOO 11S屏幕细节公布:首发三星2K E6全感屏 安卓最好的直屏手机

    日前iQOO手机官方宣布,新一代电竞旗舰iQOO 11S将会在7月4日19:00正式与大家见面。随着发布时间的日益临近,官方关于该机的预热也更加密集,截至目前已
  • iQOO 11S或7月上市:搭载“鸡血版”骁龙8Gen2 史上最强5G Soc

    去年底,iQOO推出了“电竞旗舰”iQOO 11系列,作为一款性能强机,iQOO 11不仅全球首发2K 144Hz E6全感屏,搭载了第二代骁龙8平台及144Hz电竞屏,同时在快充
  • OPPO K11采用全方位护眼屏:三大护眼能力减轻视觉疲劳

    日前OPPO官方宣布,全新的OPPO K11将于7月25日正式发布,将主打旗舰影像,和同档位竞品相比,其最大的卖点就是将配备索尼IMX890主摄,堪称是2000档位影像表
  • 联想小新Pad Pro 12.6将要推出,搭载高通骁龙 870 处理器

    联想小新Pad Pro 12.6将于秋季新品会上推出,官方按照惯例直接在发布会前给出了机型的所有参数。联想小新 Pad Pro 12.6 将搭载高通骁龙 870 处理器,重量为 5
Top