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

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

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

  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. 假如我来架构12306网站---文章来自csdn(Jackxin Xu IT技术专栏)

    (一)概论 序言:  此文的撰写始于国庆期间,当中由于工作过于繁忙而不断终止撰写,最近在设计另一个电商平台时再次萌发了完善此文并且发布此文的想法,期望自己的绵薄之力能够给予各位同行一些火花,共同推进国 ...

  2. JS模块与命名空间的介绍

    起因将代码组织到类中的一个重要原因是让代码更加“模块化”,可以在很多不同的场景中实现代码的重用.但类不是唯一的模块化代码的方式. 一般来讲,模块是一个独立的JS文件.模块文件可以包含一个类定义.一组相 ...

  3. Asp.Net MVC路由调试好帮手RouteDebugger

    Asp.Net MVC路由调试好帮手RouteDebugger 1.获取方式 第一种方法: 在程序包控制台中执行命令 PM> Install-Package routedebugger 安装成功 ...

  4. SQL Server相似度比较函数

    原文:SQL Server相似度比较函数 相似度函数 概述    最近有人问到关于两个字段求相似度的函数,所以就写了一篇关于相似度的函数,分别是“简单的模糊匹配”,“顺序匹配”,“一对一位置匹配”.在 ...

  5. 算法如功夫——C++ 用递归函数计算n的阶乘n!

    算法如功夫,套路练久了,才干应用自如! 学功夫不能死练,知其所以然,取长补短! #include <iostream.h> int main(int argc, char* argv[]) ...

  6. [Nhibernate]二级缓存

    [Nhibernate]二级缓存 目录 写在前面 文档与系列文章 二级缓存 Nhibernate二级缓存提供程序 一个例子 总结 写在前面 上篇文章介绍了nhibernate中一级缓存的相关内容,一级 ...

  7. hibernate实体类型映射文件

    1.通过写hibernate映射文件.实体类型转换为数据库中的表 据实体类型而写的. 实体类型User.java package cn.wwh.www.hibernate.dd.property; i ...

  8. Guava之简介

    1.介绍 Guava最初是在2007年作为“Google Collection  Library” 出现的,这个项目在处理Java集合时提供了一些有用的工具,Google的这个guava项目已经成为了 ...

  9. cocos2dx对于强大的RichText控制

    最近准备做一个聊天系统,开始准备使用cocos2dx的UIRichText控制显示屏聊天,在使用中发现的结果,cocos2dx的RichText很有限.全然不具备实现聊天的功能.仅仅实现了增加文本.图 ...

  10. orcale复制表结构及其数据

    http://hi.baidu.com/tag/Oracle/feeds http://hi.baidu.com/gqftuisidibabiq/item/14d306cc87cbdf45bcef69 ...