内存映射文件处理大文件

先说结论:使用内存映射文件来处理大文件可以提高效率。 

为什么呢?

我们先来看看如果不使用内存映射文件的处理流程是怎样的,首先我们得先读出磁盘文件的内容到内存中,然后修改,最后回写到磁盘上。第一步读磁盘文件是要经过一次系统调用的,它首先将文件内容从磁盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,实际上是两次数据拷贝。第三步回写也一样也要经过两次数据拷贝。

所以我们基本上会有四次数据的拷贝了,因为大文件数据量很大,几十GB甚至更大,所以拷贝的开销是非常大的。


而内存映射文件是操作系统的提供的一种机制,可以减少这种不必要的数据拷贝,从而提高效率。它由mmap()将文件直接映射到用户空间,mmap()并没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行了一次数据拷贝 ,比read进行两次数据拷贝要好上一倍,因此,内存映射的效率要比read/write效率高。


一般来说,read write操作可以满足大多数文件操作的要求,但是对于某些特殊应用领域所需要的几十GB甚至更大的存储,这种通常的文件处理方法进行处理显然是行不通的。目前,对于上述大文件的操作一般是以内存映射文件的方式来加以处理的。


内存映射,并不是将文件加载到内存。
内存映射首先申请一段地址空间,并映射到物理存储器,而这里的物理存储器就是文件所在的磁盘,类似虚拟内存(pagefile);
当有需要时,程序不需要先把它加到内存,而是直接从磁盘读取。从这里看,IO操作减少了(不需要先加载到内存)

使用内存映射文件,读取大文件
public static void main(String[] args) throws IOException { List<String> res = new ArrayList<>(); File file = new File("C:\\Users\\7q\\Desktop\\LogStat_2017-05-15_000.log"); long length = file.length(); //new RandomAccessFile(file,mode);只读方式("r"),还是以读写方式("rw"),不只是只写方式 //fileChannel.map(FileChannel.MapMode mode, long position, long size),映射方式,从什么位置开始映射,映射的范围有多大 MappedByteBuffer buffer = new RandomAccessFile(file, "r").getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < (int) length; i++) { //buffer.get(i):返回对应索引的字节 \n的ASCII为10 if (buffer.get(i) == 10) {//判断遇到换行符,处理此行数据 res.add(sb.toString()); sb.delete(0, sb.length()); } else if (i == length - 1) {//判断到了最后一行,处理此行数据 sb.append((char) buffer.get(i)); res.add(sb.toString()); sb.append((char) buffer.get(i)); } else {//拼接成一行数据 sb.append((char) buffer.get(i)); } } for (String re : res) { System.out.println(re); } }
xxxxxxxxxx
 
1
 public static void main(String[] args) throws IOException {
2
        List<String> res = new ArrayList<>();
3
        File file = new File("C:\\Users\\7q\\Desktop\\LogStat_2017-05-15_000.log");
4
        long length = file.length();
5
        //new RandomAccessFile(file,mode);只读方式("r"),还是以读写方式("rw"),不只是只写方式
6
       //fileChannel.map(FileChannel.MapMode mode, long position, long size),映射方式,从什么位置开始映射,映射的范围有多大
7
        MappedByteBuffer buffer = new RandomAccessFile(file, "r").getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
8
        StringBuilder sb = new StringBuilder();
9
        for (int i = 0; i < (int) length; i++) {
10
            //buffer.get(i):返回对应索引的字节  \n的ASCII为10
11
            if (buffer.get(i) == 10) {//判断遇到换行符,处理此行数据
12
                res.add(sb.toString());
13
                sb.delete(0, sb.length());
14
            } else if (i == length - 1) {//判断到了最后一行,处理此行数据
15
                sb.append((char) buffer.get(i));
16
                res.add(sb.toString());
17
                sb.append((char) buffer.get(i));
18
            } else {//拼接成一行数据
19
                sb.append((char) buffer.get(i));
20
            }
21
        }
22
        for (String re : res) {
23
            System.out.println(re);
24
        }
25
    }




转载于:https://www.cnblogs.com/edgedance/p/7119958.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值