您的位置:首页 > 编程语言 > Java开发

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

2014-06-02 11:16 405 查看
内存映射文件,是由一个文件到一块内存的映射。内存映射文件与虚拟内存有些类似,通过内存映射文件可以保留一个地址空间的区域,同时将物理存储器提交给此区域,内存文件映射的物理存储器来自一个已经存在于磁盘上的文件,而且在对该文件进行操作之前必须首先对文件进行映射。使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行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();
}
}
结果如下



总体来看Nio的读取和写入能力相对很快,在这里我的缓存设置比较大是能够完全读取和写入数据的大小,所以效率非常之快,在实践中可能效率要比这个要低一点,但是总体来说使用NIO的内存映射文件相对比其他方式都要快一个数量级
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: