Java中有很多读写文件或者网络流的方法,特别是Java7中加入了AIO之后,可选择的方法更多,本文的目的是想比较一下各种方式的优劣。
本文基本是参考这篇英文:http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quikcly
1.方法List
这里涉及的读文件的方法包括:
1.1 FileInputStreamOneByte
1 2 3 4 5 6 7 8 9 10 |
|
1.2 FileInputStreamBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1.3 BufferedInputStreamOneByte
1 2 3 4 5 6 7 8 9 10 |
|
1.4 BufferedInputStreamBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1.5 RandomAccessOneByte
1 2 3 4 5 6 7 8 9 10 |
|
1.6 RandomAccessBytes
1 2 3 4 5 6 7 8 9 10 11 12 |
|
1.7 FileChannelByteBufferOneByte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
1.8 FileChannelByteBufferBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
1.9 FileChannelByteBufferWrap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
1.10 FileChannelMappedByteBufferOneByte
1 2 3 4 5 6 7 8 9 10 |
|
1.11 FileChannelMappedByteBufferBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1.12 FileChannelDirectByteBufferOneByte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1.13 FileChannelDirectByteBufferBytes
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
2.测试
测试文件的大小为83M:
1 2 |
|
3.结论
得到测试数据之后,为了直观展示代码的速度,用ECharts展示,对应的js代码如下(可以在http://echarts.baidu.com/doc/example/line1.html#helianthus%E4%B8%AD%E4%BD%BF%E7%94%A8):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
|
整体展示图如下:
3.1 最快的三种方法
为了展示更细节的地方,设置了y区间范围,在yAxis上设置min和max属性:
1 2 3 4 5 6 7 8 9 10 |
|
得到如下展示图:
从上面这个图可以大致看出,最快的三种方法(PS,这里只做了一次实验,不是多次实验的平均值,所有数据可能不一定准确):
1.FileChannelMappedByteBufferBytes
2.FileChannelMappedByteBufferOneByte
3.FileChannelDirectByteBufferBytes
4.解析
下面解析一下代码中之前接触较少的东东。
4.1 RandomAccessFile
支持对文件的随机读取和写入。随机存取文件的行为类似存储在文件系统中的一个大型字节数组。存在指向该隐含数组的光标或索引,称为文件指针。
读取操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机存取文件以读取/写入模式创建,则写入操作也可用;写入操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
提供了boolean,byte,char, short, int, long, float, double这些基本类型的read和write方法。
4.2 FileChannel
FileChannel是一个连接到文件的通道。可以通过文件通道读写文件。FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下。
在使用FileChannel之前,必须先打开它。但是,我们无法直接打开一个FileChannel,需要通过使用一个InputStream、OutputStream或RandomAccessFile来获取一个FileChannel实例。
1 2 |
|
有时可能需要在FileChannel的某个特定位置进行数据的读/写操作。可以通过调用position()方法获取FileChannel的当前位置。也可以通过调用position(long pos)方法设置FileChannel的当前位置。
FileChannel实例的size()方法将返回该实例所关联文件的大小。
FileChannel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘上。出于性能方面的考虑,操作系统会将数据缓存在内存中,所以无法保证写入到FileChannel里的数据一定会即时写到磁盘上。要保证这一点,需要调用force()方法。
4.3 ByteBuffer
ByteBuffer知识下一次单独讲。
5.BufferedInputStream的defaultBufferSize
BufferedInputStream默认buffer大小为8K:
1 2 3 |
|
这个从图上也可以比较直观的看到,在缓存为8K左右的时候,性能最好:
5.参考:
http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly