java流的性能优化2-内存映射文件

内存映射文件,是由一个文件到一块内存的映射。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。

这是百度上面的解释,相对来说内存映射文件还是非常重要的,但相对于小型项目来说可能完全用不到。

NIO提供了一种将文件映射到内存的方法进行IO操作,他它比常规基于流的IO快很多,以下是几个流之间的比较:

package com.demo;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;

/**
 * 把400万条数据输入到文件中并且取出来 对比io和nio的效率
 * 当数据量过大的时候采用内存映射文件进行优化处理
 * 
 * */
public class Demo {

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		long start = System.currentTimeMillis();
		int count = 400_00000;
		String path = "e:\\temp_cache_tmp";
		String path2 = "e:\\temp_nio.tmp";
		String path3 = "e:\\temp_nio_mem.tmp";
		IoWrite(path, count);
		long end = System.currentTimeMillis();
		System.out.println("io写入时间" + (end - start));

		start = System.currentTimeMillis();
		IoRead(path, count);
		end = System.currentTimeMillis();
		System.out.println("io读取时间" + (end - start));

		start = System.currentTimeMillis();
		NioWrite(path2, count);
		end = System.currentTimeMillis();
		System.out.println("nio写入时间" + (end - start));
		
		start = System.currentTimeMillis();
		NioRead(path2, count);
		end = System.currentTimeMillis();
		System.out.println("nio读取时间" + (end - start));
		
		start = System.currentTimeMillis();
		NioMemeryWrite(path3, count);
		end = System.currentTimeMillis();
		System.out.println("nio内存映射文件写入" + (end - start));
	
		start = System.currentTimeMillis();
		NioMemeryRead(path3, count);
		end = System.currentTimeMillis();
		System.out.println("nio内存映射文件读取" + (end - start));
	}
/*
 * 内存映射文件 读取
 * */
	public static void NioMemeryRead(String path, int count)
	{
		FileChannel fc = null;
		try {
			 fc = new FileInputStream(path).getChannel();
			 IntBuffer ib = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).asIntBuffer();
			 while(ib.hasRemaining())
			 {
				 ib.get();
			 }
			 if (fc !=null) {
				fc.close();
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//内存映射文件进行写入数据
	public static void NioMemeryWrite(String path, int count)
	{
		FileChannel fc = null;;
		try {
			fc = new RandomAccessFile(path, "rw").getChannel();
			IntBuffer ib = fc.map(FileChannel.MapMode.READ_WRITE, 0, count*4).asIntBuffer();
			for (int i = 0; i < count; i++) {
				ib.put(i);
			}
			if (fc !=null) {
				fc.close();
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	/*
	 * 普通io进行读取
	 * */
	public static void IoRead(String path, int count) throws IOException {
		File file = new File(path);
		DataInputStream dis = null;
		try {
			dis = new DataInputStream(new BufferedInputStream(
					new FileInputStream(file)));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		for (int i = 0; i < count; i++) {
			dis.readInt();

		}
		dis.close();
	}

	/*
	 * 普通io进行读操作
	 */
	public static void IoWrite(String path, int count) throws IOException {
		File f = new File(path);
		if (!f.exists()) {
			try {
				f.createNewFile();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		DataOutputStream dos = null;
		try {
			dos = new DataOutputStream(new BufferedOutputStream(
					new FileOutputStream(f)));
			for (int i = 0; i < count; i++) {
				dos.writeInt(i);
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if (dos != null) {
			dos.close();
		}
	}

	public static int byte2int(byte b1, byte b2, byte b3, byte b4) {
		return ((b1 & 0xff) << 24) | ((b2 & 0xff) << 16) | ((b3 & 0xff) << 18)
				| (b4 & 0xff);
	}

	public static byte[] int2byte(int res) {
		byte[] targets = new byte[4];
		targets[3] = (byte) (res & 0xff);
		targets[2] = (byte) ((res >> 8) & 0xff);
		targets[1] = (byte) ((res >> 16) & 0xff);
		targets[0] = (byte) ((res >>> 24) & 0xff);
		return targets;
	}
/*
 * 采用Nio进行读取	
 */
	public static void NioRead(String path, int count) {
		File file = new File(path);
		FileInputStream fin = null;
		try {
			fin = new FileInputStream(file);
			FileChannel fc = fin.getChannel();
			ByteBuffer byteBuffer = ByteBuffer.allocate(count * 4);
			fc.read(byteBuffer);
			fc.close();
			byteBuffer.flip();
			while (byteBuffer.hasRemaining()) {
				byte2int(byteBuffer.get(), byteBuffer.get(), byteBuffer.get(),
						byteBuffer.get());
			}
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	/*
	 * 采用Nio进行写
	 */
	public static void NioWrite(String path, int count) throws IOException {
		File file = new File(path);
		FileOutputStream fout = null;
		try {
			fout = new FileOutputStream(file);
			FileChannel fileChannel = fout.getChannel();
			ByteBuffer byteBuffer = ByteBuffer.allocate(4 * count);
			for (int i = 0; i < count; i++) {
				byteBuffer.put(int2byte(i));
			}
			byteBuffer.flip();
			fileChannel.write(byteBuffer);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		fout.close();
	}
}
结果如下

java流的性能优化2-内存映射文件_第1张图片

总体来看Nio的读取和写入能力相对很快,在这里我的缓存设置比较大是能够完全读取和写入数据的大小,所以效率非常之快,在实践中可能效率要比这个要低一点,但是总体来说使用NIO的内存映射文件相对比其他方式都要快一个数量级

你可能感兴趣的:(java流的性能优化2-内存映射文件)