簡體   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