繁体   English   中英

为什么使用 BufferedInputStream 比使用 FileInputStream 更快地逐字节读取文件?

[英]Why is using BufferedInputStream to read a file byte by byte faster than using FileInputStream?

我试图通过使用 FileInputStream 将一个文件读入一个数组,一个 ~800KB 的文件读入内存大约需要 3 秒。 然后我尝试了相同的代码,除了 FileInputStream 包装到 BufferedInputStream 中,它花费了大约 76 毫秒。 为什么使用 BufferedInputStream 逐字节读取文件的速度要快得多,即使我仍在逐字节读取它? 这是代码(其余代码完全无关)。 请注意,这是“快速”代码。 如果您想要“慢”代码,您可以删除 BufferedInputStream :

InputStream is = null;

    try {
        is = new BufferedInputStream(new FileInputStream(file));

        int[] fileArr = new int[(int) file.length()];

        for (int i = 0, temp = 0; (temp = is.read()) != -1; i++) {
            fileArr[i] = temp;
        }

BufferedInputStream 快 30 倍以上。 远不止这些。 那么,为什么会这样,是否可以使此代码更高效(不使用任何外部库)?

FileInputStream ,方法read()读取单个字节。 从源代码:

/**
 * Reads a byte of data from this input stream. This method blocks
 * if no input is yet available.
 *
 * @return     the next byte of data, or <code>-1</code> if the end of the
 *             file is reached.
 * @exception  IOException  if an I/O error occurs.
 */
public native int read() throws IOException;

这是对使用磁盘读取单个字节的操作系统的本机调用。 这是一项繁重的操作。

使用BufferedInputStream ,该方法委托给重载的read()方法,该方法读取8192个字节并缓冲它们直到需要它们。 它仍然只返回单个字节(但保留其他字节)。 通过这种方式, BufferedInputStream对 OS 进行较少的本地调用以从文件中读取。

例如,您的文件长32768字节。 要使用FileInputStream获取内存中的所有字节,您需要对操作系统进行32768本机调用。 使用BufferedInputStream ,您将只需要4 ,而不管您将执行的read()调用次数(仍然是32768 )。

至于如何使其更快,您可能需要考虑 Java 7 的 NIO FileChannel类,但我没有证据支持这一点。


注意:如果您直接使用FileInputStreamread(byte[], int, int)方法,使用byte[>8192]不需要BufferedInputStream包装它。

包裹在 FileInputStream 周围的 BufferedInputStream 将从大块的 FileInputStream 请求数据(我认为默认情况下为 512 字节左右。)因此,如果您一次读取 1000 个字符,则 FileInputStream 只需要访问磁盘两次. 这样会快很多!

这是因为磁盘访问的成本。 假设您将拥有一个大小为 8kb 的文件。 在没有 BufferedInputStream 的情况下读取此文件将需要 8*1024 次访问磁盘。

此时,BufferedStream 就出现了,它充当了 FileInputStream 和要读取的文件之间的中间人。

一次,将获得默认为 8kb 的字节块到内存,然后 FileInputStream 将从这个中间人读取字节。 这将减少操作的时间。

private void exercise1WithBufferedStream() {
      long start= System.currentTimeMillis();
        try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
            BufferedInputStream bufferedInputStream = new BufferedInputStream(myFile);
            boolean eof = false;
            while (!eof) {
                int inByteValue = bufferedInputStream.read();
                if (inByteValue == -1) eof = true;
            }
        } catch (IOException e) {
            System.out.println("Could not read the stream...");
            e.printStackTrace();
        }
        System.out.println("time passed with buffered:" + (System.currentTimeMillis()-start));
    }


    private void exercise1() {
        long start= System.currentTimeMillis();
        try (FileInputStream myFile = new FileInputStream("anyFile.txt")) {
            boolean eof = false;
            while (!eof) {
                int inByteValue = myFile.read();
                if (inByteValue == -1) eof = true;
            }
        } catch (IOException e) {
            System.out.println("Could not read the stream...");
            e.printStackTrace();
        }
        System.out.println("time passed without buffered:" + (System.currentTimeMillis()-start));
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM