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

时间:2013-01-13 06:14:54

标签: java performance 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的性能,或者替代机制?

2 个答案:

答案 0 :(得分:14)

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

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

答案 1 :(得分:2)

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

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