为什么BufferedReader的性能比BufferedInputStream差得多?

我知道使用BufferedReader(包装FileReader)将比使用BufferedInputStream(包装FileInputStream)慢得多,因为原始字节必须转换为字符。 但我不明白为什么它这么慢! 以下是我正在使用的两个代码示例:

BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(filename)); try { byte[] byteBuffer = new byte[bufferSize]; int numberOfBytes; do { numberOfBytes = inputStream.read(byteBuffer, 0, bufferSize); } while (numberOfBytes >= 0); } finally { inputStream.close(); } 

和:

 BufferedReader reader = new BufferedReader(new FileReader(filename), bufferSize); try { char[] charBuffer = new char[bufferSize]; int numberOfChars; do { numberOfChars = reader.read(charBuffer, 0, bufferSize); } while (numberOfChars >= 0); } finally { reader.close(); } 

我已经尝试使用各种缓冲区大小的测试,所有缓冲区大小都是150兆字节的文件。 以下是结果(缓冲区大小以字节为单位;时间以毫秒为单位):

 Buffer Input Size Stream Reader 4,096 145 497 8,192 125 465 16,384 95 515 32,768 74 506 65,536 64 531 

可以看出,BufferedInputStream(64 ms)的最快时间比BufferedReader(465 ms)的最快时间快7倍。 如上所述,我没有一个显着差异的问题; 但这种差异似乎不合理。

我的问题是:有没有人建议如何提高BufferedReader的性能,或者另一种机制?

BufferedReader已将字节转换为字符。 相对于数据块的直接副本,这种逐字节解析和复制到更大类型的代价是昂贵的。

 byte[] bytes = new byte[150 * 1024 * 1024]; Arrays.fill(bytes, (byte) '\n'); for (int i = 0; i < 10; i++) { long start = System.nanoTime(); StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes)); long time = System.nanoTime() - start; System.out.printf("Time to decode %,d MB was %,d ms%n", bytes.length / 1024 / 1024, time / 1000000); } 

版画

 Time to decode 150 MB was 226 ms Time to decode 150 MB was 167 ms 

注意:必须与系统调用混合使用会降低两个操作的速度(因为系统调用可能会干扰缓存)

在BufferedReader实现中,有一个固定常量defaultExpectedLineLength = 80 ,在分配StringBuffer时用于readLine方法。 如果你的大文件有很多行超过80,那么这个片段可能是可以改进的

 if (s == null) s = new StringBuffer(defaultExpectedLineLength); s.append(cb, startChar, i - startChar);