内存映射文件-Java I/O系统

我们都知道,在内存中操作是最快的。但是平时在处理文件时,有些大文件我们无法直接放入内存中处理。这样会降低程序的速度。而内存映射文件就是为解决这个问题而生了,在用它的时候我们就可以假定那些大文件已经被放到内存中了,而且可以完全把它当成一个非常大的数组来访问。

使用方式就是,先获取通道FileChannel (写入用RandomAccessFile() 读取用FileInputStream来getChannel)

然后从FileChannel中调用map产生对应的Mapped的Buffer(如MappedByteBuffer继承ByteBuffer得到的)用来操作映射文件,这里还可以设定长度,就是可以只映射文件的一部分

下面是书上的对各种读取写入的时间性能比较

import java.io.*;
import java.nio.*;
import java.nio.channels.FileChannel;

public class MappedIO {

	//下面有写入文件的操作,这两个分别是int文字和字符文件的大小
	private static int numOfInts = 400000;
	private static int numOnUbuffInts = 20000;
	
	private abstract static class Tester {
		private String name;
		public Tester(String name) {
			this.name = name;
		}
		
		public abstract void test() throws IOException;
		
		public void runTest() {
			System.out.print(name + ":");
			
			try {
				//记录开始时间
				long start = System.nanoTime();
				//开始测试
				test();
				//计算时长
				double duration = System.nanoTime() - start;
				System.out.format("%.2f\n", duration/1.0e9);//精确到小数点后两位
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	private static Tester[] tests = {
		new Tester("Stream Write") {
			@Override
			public void test() throws IOException {
				//通过流向文件中写入数据
				DataOutputStream dos = new DataOutputStream(
						new BufferedOutputStream(
								new FileOutputStream(new File("temp.tmp"))));
				for(int i = 0; i < numOfInts; i++) {
					dos.writeInt(i);
				}
				dos.close();
			}
		},
		new Tester("Mapped Write") {
			@Override
			public void test() throws IOException {
				//获取文件通道
				FileChannel fc = new RandomAccessFile("temp.tmp", "rw").getChannel();
				//通过map产生IntBuffer,指定映射文件的初始位置和映射区域的长度
				IntBuffer ib = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()).asIntBuffer();
				for(int i = 0; i < numOfInts; i++) {
					ib.put(i);
				}
				fc.close();
			}
		},
		new Tester("Stream Read") {
			@Override
			public void test() throws IOException {
				DataInputStream dis = new DataInputStream(
						new BufferedInputStream(
								new FileInputStream(new File("temp.tmp"))));
				for(int i = 0; i < numOfInts; i++) {
					dis.readInt();
				}
				dis.close();
			}
		},
		new Tester("Mapped Read") {
			@Override
			public void test() throws IOException {
				FileChannel fc = new FileInputStream("temp.tmp").getChannel();
				IntBuffer ib = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).asIntBuffer();
				while(ib.hasRemaining()) {
					ib.get();
				}
				fc.close();
			}
		},
		new Tester("Stream Read/Write") {
			@Override
			public void test() throws IOException {
				/*
				 * 效果为先写入一个值,然后不停地复制写入前一个值
				 */
				RandomAccessFile accessFile = new RandomAccessFile(new File("temp.tmp"), "rw");
				//先写入一个1
				accessFile.writeInt(1);
				for(int i = 0; i < numOnUbuffInts; i++) {
					//int的大小为4个字节
					//先定位到上一个int的起始位置
					accessFile.seek(accessFile.length() - 4);
					//读取上一个字节,然后再文本末尾写入该值,复制的效果
					accessFile.writeInt(accessFile.readInt());
				}
				accessFile.close();
			}
		},
		new Tester("Mapped Read/Write") {
			@Override
			public void test() throws IOException {
				/*
				 * 效果为先写入一个值,然后不停地复制写入前一个值
				 */
				FileChannel fc = new RandomAccessFile("temp.tmp", "rw").getChannel();
				IntBuffer ib = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()).asIntBuffer();
				//先写入一个零
				ib.put(0);
				//i=1
				for(int i = 1; i < numOnUbuffInts; i++) {
					//取上一个的值放在当前位置
					//所以i才是从1开始
					ib.put(ib.get(i - 1));
				}
				fc.close();
			}
		}
	};
	
	public static void main(String[] args) {
		for(Tester test : tests) {
			test.runTest();
		}
	}

}



输出结果

Stream Write:0.26
Mapped Write:0.06
Stream Read:0.19
Mapped Read:0.03
Stream Read/Write:2.11
Mapped Read/Write:0.01

从结果上来看,内存映射文件的处理时间有明显的提高,特别是最后一个读写一起操作的时候




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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值