使用内存映射文件可以高效访问文件。下面代码做了一个示例,对比内存映射文件、filechannel的操作和FileOutputStream写文件的效率差异。
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileChannel.MapMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FileClient {
private FileChannel fileChannel;
private MappedByteBuffer mappedByteBuffer;
private File file;
private static int mapedFileSizeCommitLog = 1024 * 1024 * 1024;
private static final String fileName = "D:\\temp\\testfilecache\\a.dat";
private static final String fileName2 = "D:\\temp\\testfilecache\\b.dat";
private static final Logger logger = LoggerFactory.getLogger(FileClient.class.getName());
public static void main(String[] args) throws IOException {
FileClient fclient = new FileClient();
fclient.start();
fclient.start2();
}
@SuppressWarnings("resource")
public void start() throws IOException {
file = new File(fileName);
String testString = "hello";
boolean ok = false;
try {
this.fileChannel = new RandomAccessFile(this.file, "rw").getChannel();
this.mappedByteBuffer = this.fileChannel.map(MapMode.READ_WRITE, 0, mapedFileSizeCommitLog);
int curPos = 0;
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
this.mappedByteBuffer.position(curPos);
this.mappedByteBuffer.put(testString.getBytes());
curPos += 6;
}
this.mappedByteBuffer.force();
this.fileChannel.close();
long stopTime = System.currentTimeMillis();
logger.debug("time : " + (stopTime - startTime));
ok = true;
} catch (FileNotFoundException e) {
logger.error("create file channel " + fileName + " Failed. ", e);
throw e;
} catch (IOException e) {
logger.error("map file " + fileName + " Failed. ", e);
throw e;
} finally {
if (!ok && this.fileChannel != null) {
this.fileChannel.close();
}
}
}
public void start2() throws IOException {
FileOutputStream fos = new FileOutputStream(fileName2);
String testString = "hello";
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
fos.write(testString.getBytes());
}
fos.close();
long stopTime = System.currentTimeMillis();
logger.debug("time2 : " + (stopTime - startTime));
}
public void start3() throws IOException {
String input = "hello";
byte[] inputBytes = input.getBytes();
ByteBuffer buffer = ByteBuffer.wrap(inputBytes);
FileOutputStream fos = new FileOutputStream(fileName3);
FileChannel fileChannel = fos.getChannel();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 1000000; i++) {
fileChannel.write(buffer);
}
fileChannel.close();
fos.close();
long stopTime = System.currentTimeMillis();
logger.debug("time2 : " + (stopTime - startTime));
}
}
服务器sata盘,写入性能:
[root@ospservice74 ~]# dd if=/dev/zero of=kwxgd bs=64k count=4k oflag=dsync
4096+0 records in
4096+0 records out
268435456 bytes (268 MB) copied, 8.93065 seconds, 30.1 MB/s
运行后,可以看到对比结果:
[root@74 liujingyu]# java -jar filechannel-test.jar
08:25:36.029 [main] DEBUG o.l.filechannel_test.FileClient - time : 177
08:25:37.628 [main] DEBUG o.l.filechannel_test.FileClient - time2 : 1596
08:25:37.932 [main] DEBUG o.l.filechannel_test.FileClient - time2 : 304
性能相差8倍
代码可以从https://github.com/mfcliu/netty-learning下载。