读取10G的文本文件,我们可能会直接认为,这太难了,这涉及到内存的容量,硬盘的读取速度以及虚拟内存、页失败载入等概念,其实对JAVA,读取10G的文件轻而易举,无论bio(java.io)还是nio,都能轻松完成任务。
1. FileInputStream VS BufferedInputStream
不用做任何优化,也不用调用任何第三方库,FileInputStream即可独立完成工作,并且仅仅消耗内存20M。
跟FileInputStream相比,BufferedInputStream并没有体现出任何性能优势,以下是它们的成绩对比:
实现方式 | 文件大小 | 执行时间 | 消耗内存 |
FileInputStream | 9.5G | 22.826411809 | 20M |
BufferedInputStream | 9.5G | 22.60415508 | 20M |
FileInputStream的实现代码如下:
private static long readByFis(File file) throws FileNotFoundException, IOException {
InputStream is = new FileInputStream(file);
byte[] buff = new byte[4096];
long counts = 0;
int offset = 0;
while((offset = is.read(buff)) != -1) {
counts = counts + offset;
}
is.close();
return counts;
}
2. BufferedReader
对于字符处理,BufferedReader通常是我的第一选择,但从我多次测试的结果来看,字符的处理效率远远低于二进制的处理效率(内存消耗与处理时间都有较大幅度的增长),以下是成绩对比及代码实现:
实现方式 | 文件大小 | 执行时间 | 消耗内存 |
BufferedReader | 9.5G | 28.607785218S | 40M |
BufferedInputStream | 9.5G | 22.60415508 | 20M |
private static long readByBos(File file) throws FileNotFoundException, IOException {
long counts = 0;
int offset = 0;
BufferedInputStream bos = new BufferedInputStream(new FileInputStream(file));
byte[] buff = new byte[4096];
while((offset= bos.read(buff)) != -1) {
counts = counts + offset;
}
bos.close();
return counts;
}
说一句体外话,对于文件编辑器,经常出现卡顿、卡死打不开文件的原因,大部分的原因都不在于磁盘IO与内存,而在于文本处理与排版。
3. 文件通道与直接内存
在文件读取操作中,直接内存依旧没有显示出性能优势,以下是他们的成绩对比:
实现方式 | 文件大小 | 执行时间 | 缓冲区大小 |
非直接内存 | 9.5G | 27.852194903 | 2M |
非直接内存 | 9.5G | 27.083122525 | 4M |
直接内存 | 9.5G | 27.374642641 | 2M |
直接内存 | 9.5G | 27.332383289 | 4M |
现在我很怀疑,到底是JAVA对传统的IO进行了较大幅度的优化,还是nio的优势根本就不在于性能,因为读取速度上,nio表现依旧很平凡,以下是实现代码:
private static long readByChannel() throws FileNotFoundException, IOException {
long counts = 0;
File file = new File("bigFile.txt");
FileInputStream fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
ByteBuffer bbuf = ByteBuffer.allocate(2048);
int offset = 0;
while((offset = fc.read(bbuf)) != -1) {
counts = counts + offset;
bbuf.clear();
}
fc.close();
fis.close();
return counts;
}
4. 内存映射
这里的操作技巧最强,但总体来说,映射的内容越大越好,对于反复处理的内容,性能优势较为明显,这里打算单独来进行评测。
结论
读取10G的文件,JAVA的传统API即可轻松完成,并且性能卓越,至于NIO,强化的可能不仅仅是性能,而是新的编程方式与阻塞处理机制。