为什么使用 BufferedInputStream 逐字节读取文件的速度比使用 FileInputStream 快?

2022-08-31 13:38:28

我尝试使用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 倍以上。远不止于此。那么,为什么会这样,是否有可能使此代码更有效率(不使用任何外部库)?


答案 1

在 中,该方法读取单个字节。从源代码:FileInputStreamread()

/**
 * 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;

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

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

例如,您的文件长度为字节。要获取内存中带有 的所有字节,您需要对操作系统进行本机调用。有了 ,您将只需要 ,而不管您将执行的呼叫次数(仍然)。32768FileInputStream32768BufferedInputStream4read()32768

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


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


答案 2

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