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

时间:2013-09-03 19:47:54

标签: java file-io inputstream 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多倍。远不止于此。那么,为什么会这样,并且可以使这个代码更有效(不使用任何外部库)?

3 个答案:

答案 0 :(得分:105)

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;

这是对OS的本机调用,它使用磁盘读取单个字节。这是一项繁重的行动。

使用BufferedInputStream,该方法委托给重载的read()方法,该方法读取8192个字节并缓冲它们直到需要它们为止。它仍然只返回单个字节(但保留其他字节)。这样,BufferedInputStream对操作系统的本机调用较少,无法从文件中读取。

例如,您的文件长度为32768个字节。要使用FileInputStream获取内存中的所有字节,您需要对操作系统进行32768本机调用。使用BufferedInputStream,您只需要4,无论您要执行的read()次呼叫数量是多少(仍为32768)。

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

答案 1 :(得分:2)

围绕FileInputStream的BufferedInputStream将以大块的形式从FileInputStream请求数据(我认为默认情况下为512字节左右。)因此,如果您一次读取一个1000个字符,则FileInputStream只需要转到磁盘两次。这会快得多!

答案 2 :(得分:0)

这是因为磁盘访问的成本。让我们假设您将拥有一个大小为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));
    }
相关问题