BufferedInputStream 的使用

Posted

技术标签:

【中文标题】BufferedInputStream 的使用【英文标题】:Usage of BufferedInputStream 【发布时间】:2017-08-15 18:18:59 【问题描述】:

让我在这篇文章的开头谨慎一点。当谈到 Java 时,我是一个完全的初学者。我一直在断断续续地编写 php 编程,但我已经准备好制作一个桌面应用程序,所以出于各种原因我决定使用 Java。

我正在处理的应用程序处于初始阶段(少于 5 个类),我需要从本地文件中读取字节。通常,这些文件当前小于 512kB(但将来可能会变得更大)。目前,我正在使用FileInputStream 将文件读入三字节数组,完全满足我的要求。但是,我看到提到了BufferedInputStream,我想知道我目前这样做的方式是否最好,或者我是否也应该使用BufferedInputStream

我已经做了一些研究,并在 Stack Overflow 上阅读了一些问题,但我仍然无法理解何时使用和不使用 BufferedInputStream 的最佳情况。在我的情况下,我读取字节的第一个数组只有几个字节(小于 20)。如果我收到的数据在这些字节中是好的,那么我将文件的其余部分读入另外两个不同大小的字节数组。

我还听到很多人提到分析,以查看在每种特定情况下哪个更有效,但是,我没有分析经验,我不确定从哪里开始。我也希望对此提出一些建议。

很抱歉发了这么长的帖子,但我真的很想学习和理解做这些事情的最佳方法。我总是有第二次猜测我的决定的坏习惯,所以我希望得到一些反馈。谢谢!

【问题讨论】:

【参考方案1】:

如果您一直在进行少量读取,那么BufferedInputStream 将为您提供显着更好的性能。无缓冲流上的每个读取请求通常会导致对操作系统的系统调用以读取请求的字节数。进行系统调用的开销可能是每个系统调用数千条机器指令。缓冲流通过对内部缓冲区进行一次大读取(例如)最多 8k 字节,然后从该缓冲区分发字节来减少这种情况。这可以大大减少系统调用的数量。

但是,如果您一直在进行大量读取(例如 8k 或更多),那么 BufferedInputStream 会稍微减慢速度。您通常不会减少系统调用的数量,而且缓冲会引入额外的数据复制步骤。

在您的用例中(您首先读取 20 字节块,然后读取大量大块)我会说使用 BufferedInputStream 更有可能降低性能而不是提高性能。但最终,这取决于实际的读取模式。

【讨论】:

However, if you are consistently doing large reads (e.g. 8k or more) then a BufferedInputStream slows things. 怎么样? 看代码!调用中有一个额外的间接级别,额外的工作是检查缓冲区中是否有任何东西等。幸运的是,代码足够聪明,可以避免不必要的复制,尽可能使用 InputStream API。因此,相对减速很小,但可以衡量。【参考方案2】:

如果您使用相对较大的数组一次读取一个块的数据,那么BufferedInputStream 只会引入一个浪费的副本。 (请记住,read 不一定会读取所有数组 - 您可能需要DataInputStream.readFully)。 BufferedInputStream 在进行大量小读取时获胜。

【讨论】:

我想我明白你在说什么。让我再问你一个问题。我看到了 FileInputStream 的构造函数,它以 byte[] 作为参数。目前,我正在使用 for 循环来读取所需的字节,但是,我假设使用此参数会更有效?我还假设使用 for 循环不断地从 FileInputStream 调用 read 就是你所说的大量小读取的意思?我很抱歉听起来如此幼稚,但由于某种原因,我很难完全掌握这一点。感谢您的回答! @mastermosaj 您可能会看到ByteArrayInputStream 的构造函数,它是一个InputStream,它通过byte[] 读取,所以没有实际的I/O。如果您逐字节阅读byte[],那么您可能会发现使用BufferedInputStreamByteArrayInputStream 会以一定的性能成本简化您的代码。 (注意不要将BufferedInputStream 与底层流混合使用,因为前者会缓冲。【参考方案3】:

BufferedInputStream 会提前读取更多您需要的文件。据我了解,它提前做了更多的工作,比如 1 个大的连续磁盘读取,而不是在一个紧密的循环中做很多。

至于分析 - 我喜欢 netbeans 中内置的分析器。这真的很容易上手。 :-)

【讨论】:

感谢您的建议。我听说有人提到 NetBeans 中的分析器。我开始使用 NetBeans,但是,我暂时只使用纯文本编辑器。我觉得我通过这种方式学到了更多关于语言的知识。您还有其他建议吗? 文本编辑器很棒,但如果您要向客户收费,这有点像踩自卸卡车。如果您想避免在 ide 中进行分析,您可以尝试 hprof:java.sun.com/developer/technicalArticles/Programming/HPROF.html 谢谢@jskaggz。我会检查hprof。顺便说一句,我正在为自己制作这个应用程序,所以我并没有真正的时间表,但我同意如果它是为客户准备的,我肯定会使用 ide 来加速它。【参考方案4】:

我无法谈论分析,但根据我开发 Java 应用程序的经验,我发现使用任何缓冲区类 - BufferedInputStream、StringBuffer - 我的应用程序都异常快。因此,即使是最小的文件或字符串操作,我也会使用它们。

【讨论】:

在使用BufferedInputStream时,通常是指定一个特定大小的chunk给它缓冲,还是让它自动决定? 这取决于。正如 Stephen C 上面所说的,如果这个数字与系统调用中使用的数据页大小(比如 4k)不一致,那么您只会通过创建瓶颈来打自己的脚。把它想象成用铲子装满沙袋。如果您将太多或太少的沙子舀到铲子上,您只会降低效率/性能。顺便说一句,我提倡编写好的代码。但是,如果您刚刚开始,那么让它工作并稍后进行优化并没有错。这些东西可能是兔子洞。 @JasonMcCreary 何时使用read() 逐字节以及何时使用read(byte[]) 字节数组。因为我认为阅读数组总是更好。那么你能给我举个例子,在哪里使用read()逐字节或read(byte[])字节数组。或BufferedInputStream.?【参考方案5】:
    import java.io.*;
    class BufferedInputStream
    
            public static void main(String arg[])throws IOException
            
                FileInputStream fin=new FileInputStream("abc.txt");
                BufferedInputStream bis=new BufferedInputStream(fin);
                int size=bis.available();
                while(true)
                
                        int x=bis.read(fin);
                        if(x==-1)
                        
                                bis.mark(size);
                                System.out.println((char)x);
                        
                
                        bis.reset();
                        while(true)
                        
                                int x=bis.read();
                                if(x==-1)
                                
                                    break;
                                    System.out.println((char)x);
                                
                        

            

    

【讨论】:

打扰一下 - 这是什么?

以上是关于BufferedInputStream 的使用的主要内容,如果未能解决你的问题,请参考以下文章

BufferedInputStream读取流正常,但是BufferedInputStream转化为BufferedReader后 就读取不到数据了?求解

如何终止 BufferedInputStream .read() 调用

文件流之字节缓冲流(BufferedInputStream BufferedOutputStream)

OutputStream-InputStream-FileOutputStream-FileInputStream-BufferedOutputStream-BufferedInputStream-四

bufferedinputstream的使用

BufferedInputStream 中的读取方法