我们如何使用挂钩来提高性能?

时间:2014-03-06 13:08:40

标签: java bufferedreader filereader

Java Docs说Java Docs

  

公共类BufferedReader   扩展阅读器

     

从字符输入流中读取文本,缓冲字符,以便提供>高效读取字符,数组和行。

     

可以指定缓冲区大小,也可以使用默认大小。默认值很大>足以满足大多数用途。

     

通常,由读取器构成的每个读取请求使得相应的读取请求>由基础字符或字节流构成。因此,建议在其read()操作可能成本较高的任何Reader周围包装一个> BufferedReader,例如> FileReaders和InputStreamReaders。例如,

     

BufferedReader in   = new BufferedReader(new FileReader(“foo.in”));

     

将缓冲指定文件的输入。如果没有缓冲,每次调用> read()或readLine()都可能导致从文件中读取字节,转换为>字符,然后返回,这可能效率非常低。

但是通过挂钩Filereader,我们使用FileReader的read方法来读取一次读取一个字符的文件,所以如果我的文件包含2000个字符,FileReader首先会一次读取一个2000个字符并将其传输到缓冲区,我们会读取来自缓冲区使用bufferedreader那么它如何增强性能。我们只能使用FileReader吗?

4 个答案:

答案 0 :(得分:2)

你可以想象它:

您位于A位置,而您的数据位于B位置AB彼此相距5公里。

通过一次一个单位撤消数据,你必须每次从AB进行旅行(读取基础字符或字节流的请求),因此如果你有100个数据单位,你将要做100次旅行,这是花费时间。

Wehen Buffering你就像拥有一辆卡车,当你做旅行时,你需要将一些数据单元(缓冲区的大小)加载到你的载货地板(缓冲区)上,这样你就不必去旅行了。很多次,因此效率很高。

通常在打开文件进行阅读时,您想要阅读更多的字符,因此首选BufferedRead。

这同样适用于写作。

修改

首先,FileReader不读取自身,它是底层输入流。在这种情况下FileInputStream

BufferedReader为您管理FileReasder,并在其fill()方法中使用方法

abstract public int read(char cbuf[], int off, int len) throws IOException;
你的Reader

填补了缓冲区。 它不使用只读取单个字符的方法!换句话说,当填充方法必须执行 travel 时,它会从底层检索一系列字符输入流并将其保存在内存中,这样当您需要读取时,它首先在缓冲区中查找,使用它并在必要时重新填充它。

你可以通过自己调用read(char cbuf[], int off, int len) FileReader来实现同样的目标,但是你所拥有的只是一系列具有例如以下文字的字符

Lorem ipsum dolor sit amet, consetetur sadipscing elitr,
sed diam nonumy eirmod tempor invidunt ut labore et dolore
magna aliquyam erat, sed diam voluptua.
例如,

可能看起来像这样

"onsetetur sadipscing elitr,\r\nsed diam nonumy eirmod temp"

如果需要,你必须处理它才能找到一行文字。

但是你没有必要因为BufferedReader为你照顾这个,这就是为什么你最好写的原因之一

BufferedReader in = new BufferedReader(new FileReader("foo.in"));

答案 1 :(得分:2)

BufferedReader是使用缓冲区的常见示例。

让我们分解BufferedReader(J7u51)的read()方法:

ensureOpen();
for (;;) {
    if (nextChar >= nChars) {
        fill();
        if (nextChar >= nChars)
            return -1;
    }

当且仅当我们要求的字符超过以前的一些调用时才会调用fill()方法(调用底层读者)。

    if (skipLF) {
        skipLF = false;
        if (cb[nextChar] == '\n') {
            nextChar++;
            continue;
        }
    }
    return cb[nextChar++];
}

这里我们只返回适当的值。

所以BufferedReader总是“在你想要更多的时候阅读更多内容”然后,如果你真的想要更多,那么可以给你“更有效”。

看一下这个例子:

YourApp                   BufferedReader (bufferSize=10)        FileReader
read(1 character)   ->
                          buffer empty, load 10 characters  ->  disk latency 10 ms
                                                            <-  return 10 characters
                          buffer filled with 10 characters
                    <-    return 1 character, 9 remaining 
                          in buffer
read(1 character)   ->    
                    <-    return 1 character, 8 remaining 
                          in buffer
.
.
.
read(1 character)   ->    
                    <-    return 1 character, 0 remaining 
                          in buffer

循环的总执行时间是10毫秒+无关紧要的Java开销。

现在,将它与无缓冲版本进行比较:

YourApp                   FileReader

read(1 character)   ->
                          disk latency 10 ms
                    <-    return 1 character
read(1 character)   ->    
                          disk latency 10 ms
                    <-    return 1 character
.
.
.
read(1 character)   ->    
                          disk latency 10 ms
                    <-    return 1 character

HDD调用导致的开销远大于前一种情况。

答案 2 :(得分:1)

首先,BufferedReader不会一次完全读取已包装的Reader。相反,如果需要,它会读取特定大小的块(默认为8192个字符)。

其次,使用BufferedReader而不是直接使用FileReader的原因是访问文件比访问内存中的对象要复杂得多。因此,如果您逐行读取文件,则每行访问一次文件系统。使用BufferedReader,可以减少读取操作的数量,从而提高代码的性能。

答案 3 :(得分:1)

谁说FileReader个实例将用于一次读取一个字符?

您问题的最佳解决方案是直接转到BufferedReader的源代码。如果您对此进行调查,您会在内部看到BufferedReader将调用已包装read(char[],int,int)的{​​{1}}方法(或其所包含的FileReader)。

Here您拥有Reader read方法的代码。对BufferedReader包裹Reader的实际调用是在fill方法中执行的。我认为值得检查一下。