Java NIO之内存映射文件——MappedByteBuffer
2017-01-11 11:07
1111 查看
大多数操作系统都可以利用虚拟内存实现将一个文件或者文件的一部分"映射"到内存中。然后,这个文件就可以当作是内存数组来访问,这比传统的文件要快得多。
内存映射文件的一个关键优势是操作系统负责真正的读写,即使你的程序在刚刚写入内存后就挂了,操作系统仍然会将内存中的数据写入文件系统。另外一个更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。
那么,如何将一个文件映射到内存呢?
从文件中获得一个通道(channel)
这里options指定映射模式,支持的模式有三种:
FileChannel.MapMode.READ_ONLY:所产生的缓冲区是只读的。
FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的,任何修改都会在某个时刻写回到文件中。
注意,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的确切行为是依赖
于操作系统的。
FileChannel.MapMode.PRIVATE:所产生的缓冲区是可写的,但是任何修改对该缓冲区来说都是私有的,不
会传播到文件中。
调用FileChannel的map方法
接下来通过计算一个40MB文件的CRC32校验和来比较传统的文件输入和内存映射文件的速度。
传统的文件输入包括:
普通输入流(InputStream)
带缓冲的输入流(BufferedInputStream)
随机访问文件(RandomAccessFile)
程序如下:
输出结果如下:
可以明显看出,内存映射文件速度比普通输入流和随机访问文件快得多,比带缓冲的输入流稍微快一些。
内存映射文件的一个关键优势是操作系统负责真正的读写,即使你的程序在刚刚写入内存后就挂了,操作系统仍然会将内存中的数据写入文件系统。另外一个更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。
那么,如何将一个文件映射到内存呢?
从文件中获得一个通道(channel)
java FileChannel channel = FileChannel.open(path,options);
这里options指定映射模式,支持的模式有三种:
FileChannel.MapMode.READ_ONLY:所产生的缓冲区是只读的。
FileChannel.MapMode.READ_WRITE:所产生的缓冲区是可写的,任何修改都会在某个时刻写回到文件中。
注意,其他映射同一个文件的程序可能不能立即看到这些修改,多个程序同时进行文件映射的确切行为是依赖
于操作系统的。
FileChannel.MapMode.PRIVATE:所产生的缓冲区是可写的,但是任何修改对该缓冲区来说都是私有的,不
会传播到文件中。
调用FileChannel的map方法
java 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
可以明显看出,内存映射文件速度比普通输入流和随机访问文件快得多,比带缓冲的输入流稍微快一些。
相关文章推荐
- android任意地方退出app
- 微信小程序开发初体验
- css 禁用移动端部分特性
- android-错误:refused to install the app by The ADB command !
- Android Studio运行出现Unknown run configuration type AndroidRunConfigurationType解决方案
- 移动端模拟导航可点击自动滑动
- php 判断是移动端还是pc端访问web页面
- WebView启动支付宝客户端支付失败的问题小结
- 【Unity】让手机游戏屏幕常亮
- 微信常用功能总结
- android_66_girl_dress_up
- iOS10适配系列教程
- iOS9适配系列教程
- 微信小程序之Mustache
- lambda表达式介绍以及Android Studio引入lambda
- Android编译--刷机--改代码--再刷机,随笔相关查找
- 一步步构建iOS路由
- android中的数据存储(SharePreferences,本地,和数据库)
- 几个iOS的内存工具粗略介绍
- Android实现数据存储技术