大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中。然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多。

内存映射文件的一个关键优势是操作系统负责真正的读写,即使你的程序在刚刚写入内存后就挂了,操作系统仍然会将内存中的数据写入文件系统。另外一个更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。

那么,如何将一个文件映射到内存呢?

  1. 从文件中获得一个通道(channel)
FileChannel channel = FileChannel.open(path,options);

这里options指定映射模式,支持的模式有三种:

  • FileChannel.MapMode.READ_ONLY:所产生的缓冲区是只读的。
  • FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的,任何修改都会在某个时刻写回到文件中。

    注意,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的确切行为是依赖

    于操作系统的。
  • FileChannel.MapMode.PRIVATE:所产生的缓冲区是可写的,但是任何修改对该缓冲区来说都是私有的,不

    会传播到文件中。
  1. 调用FileChannel的map方法
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,length);

接下来通过计算一个40MB文件的CRC32校验和来比较传统的文件输入和内存映射文件的速度。

传统的文件输入包括:

  • 普通输入流(InputStream)
  • 带缓冲的输入流(BufferedInputStream)
  • 随机访问文件(RandomAccessFile)

程序如下:

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.CRC32; /**
* Created by lbd on 2017/1/11.
*/
public class MemoryMapTest {
public static long checksumInputStream(Path filename) throws IOException { //普通输入流
try (InputStream in = Files.newInputStream(filename)) {
CRC32 crc = new CRC32();
int c;
while ((c = in.read()) != -1)
crc.update(c);
return crc.getValue();
}
} public static long checksumBufferedInputStream(Path filename) throws IOException { //带缓冲的输入流
try (BufferedInputStream in = new BufferedInputStream(Files.newInputStream(filename))){
CRC32 crc = new CRC32();
int c;
while ((c = in.read()) != -1)
crc.update(c);
return crc.getValue();
}
} public static long checksumRandomAccessFile(Path filename) throws IOException { //随机访问文件
try (RandomAccessFile file = new RandomAccessFile(filename.toFile(),"r")){
CRC32 crc = new CRC32();
long length = file.length(); for (long p = 0; p < length; p++){
file.seek(p);
int c = file.readByte();
crc.update(c);
}
return crc.getValue();
}
} public static long checksumMappedFile(Path filename) throws IOException { //内存映射文件
try (FileChannel channel = FileChannel.open(filename)){
CRC32 crc = new CRC32();
int length = (int)channel.size();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY,0,length); for (int p = 0; p < length; p++){
int c = buffer.get(p);
crc.update(c);
}
return crc.getValue();
}
} public static void main(String[] args) throws IOException {
System.out.println("Input Stream:");
long start = System.currentTimeMillis();
Path filename = Paths.get(args[0]);
long crcValue = checksumInputStream(filename);
long end = System.currentTimeMillis();
System.out.println(Long.toHexString(crcValue));
System.out.println((end - start) + " milliseconds");
System.out.println(); System.out.println("Buffered Input Stream:");
start = System.currentTimeMillis();
crcValue = checksumBufferedInputStream(filename);
end = System.currentTimeMillis();
System.out.println(Long.toHexString(crcValue));
System.out.println((end - start) + " milliseconds");
System.out.println(); System.out.println("Random Access File:");
start = System.currentTimeMillis();
crcValue = checksumRandomAccessFile(filename);
end = System.currentTimeMillis();
System.out.println(Long.toHexString(crcValue));
System.out.println((end - start) + " milliseconds");
System.out.println(); System.out.println("Mapped File:");
start = System.currentTimeMillis();
crcValue = checksumMappedFile(filename);
end = System.currentTimeMillis();
System.out.println(Long.toHexString(crcValue));
System.out.println((end - start) + " milliseconds");
}
}

输出结果如下:

Input Stream:
c644b1f1
42317 milliseconds Buffered Input Stream:
c644b1f1
329 milliseconds Random Access File:
c644b1f1
57781 milliseconds Mapped File:
c644b1f1
207 milliseconds

可以明显看出,内存映射文件速度比普通输入流和随机访问文件快得多,比带缓冲的输入流稍微快一些。

Java NIO之内存映射文件——MappedByteBuffer的更多相关文章

  1. JAVA NIO FileChannel 内存映射文件

      文件通道总是阻塞式的. 文件通道不能创建,只能通过(RandomAccessFile.FileInputStream.FileOutputStream)getChannel()获得,具有与File ...

  2. 内存映射文件MappedByteBuffer和Buffer的Scattering与Gathering

    上一篇讲到的DirectByteBuffer继承自MappedByteBuffer 一.MappedByteBuffer MappedByteBuffer的定义: A direct byte buff ...

  3. JAVA NIO之浅谈内存映射文件原理与DirectMemory

    JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...

  4. NIO之通道(Channel)的原理与获取以及数据传输与内存映射文件

    通道(Channel) 由java.nio.channels包定义的,Channel表示IO源与目标打开的连接,Channel类似于传统的“流”,只不过Channel本身不能直接访问数据,Channe ...

  5. Java-NIO(五):通道(Channel)的数据传输与内存映射文件

    通道(Channel)的数据传输(采用非直接缓冲区) @Test public void testChannel() throws IOException { FileInputStream file ...

  6. 内存映射文件(Memory-Mapped File)

    Java Memory-Mapped File所使用的内存分配在物理内存而不是JVM堆内存,且分配在OS内核. 1: 内存映射文件及其应用 - 实现一个简单的消息队列 / 计算机程序的思维逻辑 在一般 ...

  7. 【JavaNIO的深入研究4】内存映射文件I/O,大文件读写操作,Java nio之MappedByteBuffer,高效文件/内存映射

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件.有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问.这种解决办法能大大简化修改文件的代码.fileC ...

  8. Java NIO 内存映射文件

    Java NIO 内存映射文件 @author ixenos 文件操作的四大方法 前提:内存的访问速度比磁盘高几个数量级,但是基本的IO操作是直接调用native方法获得驱动和磁盘交互的,IO速度限制 ...

  9. Java编程的逻辑 (61) - 内存映射文件及其应用 - 实现一个简单的消息队列

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

随机推荐

  1. MVC页面声命周期

    MVC页面声命周期 ASP.Net请求处理机制初步探索之旅 - Part 4 WebForm页面生命周期   开篇:上一篇我们了解了所谓的请求处理管道,在众多的事件中微软开放了19个重要的事件给我们, ...

  2. IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权

    原文:IS2009制作Oracle 静默安装包(一)感谢空白先生特许授权 上一篇: MyEclipse中消除frame引起的“the file XXX can not be found.Please ...

  3. Android学习小Demo(21)ListView的联动选择

    在日常的App开发中,尤其是在开发生活服务的应用上,非常多时候,我们会须要联动地展现省市区的数据等,需求大概例如以下: 1)展现全部省份 2)当点击某省份的时候,在二级菜单上展现此省份以下所属的城市列 ...

  4. 使用 C# 进行 Outlook 2007 编程

    原文:使用 C# 进行 Outlook 2007 编程 探讨如何使用 C# 编程语言生成 Outlook 识别的应用程序和 Outlook 外接程序. 请从"Add References&q ...

  5. Linux下查看使用频率最高的十个命令

    这个shell是在linux吧一个小伙伴发的,链接已找不到,挺有意思的,隔段时间运行一次,可以看看自己最近都干了什么. [shell] history | awk '{CMD[$2]++;count+ ...

  6. MySQL之 ALTER vs CHANGE vs MODIFY COLUMN

    1.ALTER COLUMN 用于设置或者移除某一列的默认(缺省)值, 1.1用法 ALTER TABLE MyTable ALTER COLUMN foo SET DEFAULT 'bar'; AL ...

  7. EnterpriseLibrary 6.0(微软企业库6.0学习笔记) 之Data Access Block 配置和获取链接字符串

    EnterpriseLibrary 的特点是快速开发,融合了微软工程师多年的经验,现在在微软内部有专门的一个小组在完善EnterpriseLibray,最近的更新时间是April 2013. 相关链接 ...

  8. WinXP 无线技巧“区域没有通过无线网络中的发现”一个可能的原因!

    貌似WinXP经典或无限.我一直沿用至今,我不知道这一天会放弃. 遇到的问题,也许有XP爱好者都遇到过还得看,写下一点文字注释.----------------------- 切割线 -------- ...

  9. linux下搭建SVN服务器完全手册-很强大!!!!!

    系统环境        RHEL5.4最小化安装(关iptables,关selinux) + ssh + yum 一,安装必须的软件包.        yum install subversion ( ...

  10. Android L新控件RecyclerView简介

    Android L是android进化史上的里程碑,尽管还没有正式发布4.5或者5.0,但预览版也同样精彩. 这篇文章只是另外一篇博客的总结性翻译,能够读懂原文的,可以点开这个链接去阅读精彩的原文:h ...