【问题标题】:How Buffer Streams works internally in JavaBuffer Streams 如何在 Java 内部工作
【发布时间】:2015-12-24 07:54:49
【问题描述】:

我正在阅读有关Buffer Streams 的信息。我搜索了一下,发现很多答案都清楚了我的概念,但还有一点问题。

经过搜索,我了解到,Buffer 是临时内存(RAM),它可以帮助程序快速读取数据而不是硬盘。当 Buffers 为空时,则为原生 input API is called

在阅读了更多内容后,我得到了答案from here

从磁盘逐字节读取数据效率非常低。一种方法 加快速度是使用缓冲区:而不是一次读取一个字节, 您一次读取几千个字节,并将它们放入缓冲区中 记忆。然后就可以一个一个的查看缓冲区中的字节了。

我有两个困惑,

1:如何/谁在缓冲区中填充数据? (原生 API 怎么样?)正如上面引用的那样,谁一次填充了数千个字节?它会消耗相同的时间。假设我有 5MB 数据,并且 5MB 在 5 秒内加载到 Buffer 中。然后程序在 5 秒内使用缓冲区中的这些数据。总共10秒。但是如果我跳过缓冲,那么程序在 1MB/2 秒内从硬盘获取直接数据,与总共 10 秒相同。请解开我的困惑。

2:第二条这条线是如何工作的

BufferedReader inputStream = new BufferedReader(new FileReader("xanadu.txt"));

我在想 FileReader 将数据写入缓冲区,然后 BufferedReader 从缓冲存储器中读取数据?也解释一下。

谢谢。

【问题讨论】:

    标签: java buffer


    【解决方案1】:

    所有的东西都是由一个名为fill()的私有方法完成的,我给你的目的是为了教育目的,但所有的java IDE都让你自己看源代码:

    private void fill() throws IOException {
        int dst;
        if (markedChar <= UNMARKED) {
            /* No mark */
            dst = 0;
        } else {
            /* Marked */
            int delta = nextChar - markedChar;
            if (delta >= readAheadLimit) {
                /* Gone past read-ahead limit: Invalidate mark */
                markedChar = INVALIDATED;
                readAheadLimit = 0;
                dst = 0;
            } else {
                if (readAheadLimit <= cb.length) {
                    /* Shuffle in the current buffer */
      // here copy the read chars in a memory buffer named cb
                    System.arraycopy(cb, markedChar, cb, 0, delta);
                    markedChar = 0;
                    dst = delta;
                } else {
                    /* Reallocate buffer to accommodate read-ahead limit */
                    char ncb[] = new char[readAheadLimit];
                    System.arraycopy(cb, markedChar, ncb, 0, delta);
                    cb = ncb;
                    markedChar = 0;
                    dst = delta;
                }
                nextChar = nChars = delta;
            }
        }
    
        int n;
        do {
            n = in.read(cb, dst, cb.length - dst);
        } while (n == 0);
        if (n > 0) {
            nChars = dst + n;
            nextChar = dst;
        }
    }
    

    【讨论】:

    • 对不起,我无法从您的回答中消除我的困惑。
    • 对不起!你需要知道,真正的东西是由计算机自己做的,是C语言代码的本地方法,并且依赖于每个操作系统,也许它会消除一些混乱?一个简单的例子:public static native void java.lang.System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
    • 但是我的时间混乱是怎么回事?
    • 你可以看到,只有一个Operation是原生的,处理所有的数据。在每个操作系统上的每个实现都可以处理它之后,所以你需要看看它在 C 中的真正作用。我们可以安静地确定效率是否正确完成?
    • fill 方法何时被调用,是谁调用的?
    【解决方案2】:

    至于在读/写期间使用缓冲的性能,它可能影响最小,因为操作系统也会缓存,但是缓冲会减少对操作系统的调用次数,这会产生影响。

    当您在顶部添加其他操作时,例如字符编码/解码或压缩/解压缩,影响更大,因为这些操作在块中完成时效率更高。


    你第二个问题说:

    我在想 FileReader 将数据写入缓冲区,然后 BufferedReader 从缓冲存储器中读取数据?也解释一下。

    我相信你的想法是错误的。是的,从技术上讲,FileReader 会将数据写入 a 缓冲区,但该缓冲区不是由 FileReader 定义的,而是由 FileReader.read(buffer) 方法的调用者定义的。

    当一些代码调用BufferedReader.read()(任何重载)时,操作从外部启动。然后 BufferedReader 将检查它的缓冲区,如果缓冲区中有足够的数据可用,它将返回不涉及 FileReader 的数据。如果需要更多数据,BufferedReader 会调用FileReader.read(buffer) 方法获取下一块数据。

    这是一个拉操作,而不是一个推,这意味着数据是由调用者从读取器中拉出来的。

    【讨论】:

      猜你喜欢
      • 2014-11-22
      • 2020-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-25
      • 2017-05-03
      • 1970-01-01
      • 2022-12-07
      相关资源
      最近更新 更多