Java 的 BufferedReader 和 InputStreamReader 类有啥区别?
Posted
技术标签:
【中文标题】Java 的 BufferedReader 和 InputStreamReader 类有啥区别?【英文标题】:What is the difference between Java's BufferedReader and InputStreamReader classes?Java 的 BufferedReader 和 InputStreamReader 类有什么区别? 【发布时间】:2011-11-14 15:41:48 【问题描述】:Java 的BufferedReader
和InputStreamReader
类有什么区别?
【问题讨论】:
也告诉 Abt DataInputStream 类 @amod0017 这个问题在 Javadoc 中得到了完整的回答。不鼓励在产品文档中有明确答案的论坛上提问,这是一种非常不好的习惯。只会浪费宝贵的时间。正确的答案已经在 Javadoc 中,这里的任何响应都会逐字引用它,OP 可能已经阅读过,或者解释它,这是价值和精度的损失。并提出一个您可以在论坛上回答自己的问题,并可能永远等待一个可能不正确的答案。不是一个理性的学习策略。 @EJB 我同意你的观点,但我想提出的问题是以错误的方式提出的......他对某些 Web 应用程序有一些特殊的输入,他只是想问他应该更喜欢哪个...因为他在两者之间感到困惑...就这么简单。 如果我重新表述这个问题,我会问:“在什么情况下我不想缓冲输入流阅读器?”似乎默认情况下几乎所有地方都使用缓冲区。 @AjayYadav 您能否将接受的答案更改为 ChaitanyaVaishampayan 的答案。完全取决于你,但是,也许你需要重新审视他解释得如此详细的答案。 【参考方案1】:BufferedReader 是“InputStreamReader/FileReader”的包装器,它会在每次调用本机 I/O 时缓冲信息。
您可以想象读取一个字符(或字节)与读取一个大数字的效率差异。一次性(或字节)中的字符数。使用BufferedReader,如果你想读取单个字符,它将存储内容以填充其缓冲区(如果它是空的),并且对于进一步的请求,将直接从缓冲区中读取字符,从而获得更高的效率。
InputStreamReader 将字节流转换为字符流。它读取字节并使用指定的字符集将它们解码为字符。它使用的字符集可以由名称指定,也可以显式给出,或者可以接受平台的默认字符集。
希望对你有帮助。
【讨论】:
amod 我想使用这些类来存储网页的内容。我想知道我应该使用 BufferedReader 还是 InputStreamReader ? @ajay 我对此不太确定......但我在某处读到 BufferReader 是有效的。 对于竞争性编码,我应该使用 BufferedReader 还是 InputReader【参考方案2】:从主内存读取比从磁盘/STDIN 读取要快。
BufferedReader
使用一种称为 buffering 的技术,它允许我们通过将块复制到主内存来减少从磁盘/STDIN 读取的频率。
考虑:
BufferedReader in = new InputStreamReader(System.in);
in.read(); //
in.read(); //
// ...
in.read(); // could be hitting the disk/STDIN a lot (slow!)
对比:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
in.read(); //
in.read(); //
// ...
in.read(); // hitting main memory a lot (fast!)
来自documentation:
如果没有缓冲,
read()
的每次调用都可能导致从 [disk/STDIN] 读取字节,转换为字符,然后返回,效率可能非常低强>.
这两个类实现了Reader
的相同接口。因此,虽然您可以只使用 InputStreamReader
而不使用 BufferedReader
,但可能会导致性能不佳。我们只是在这里使用decorator pattern,所以我们最终得到一个InputStreamReader
,它现在具有缓冲能力。
【讨论】:
【参考方案3】:InputStreamReader 类将InputStream 类型(未解释的字节)适应Reader 类(字节解释为某些字符集中的字符),但不应用任何额外的缓冲。 BufferedReader 类采用 Reader 类(可能是无缓冲的)并对其应用缓冲。
【讨论】:
“缓冲”是什么意思? 缓冲意味着数据聚集在一个称为“缓冲区”的数组中。使用缓冲区可以提高读取效率,因为您一次将大块从网络复制到缓冲区,即使您一次只从缓冲区读取少量数据。它还可以重新读取已经使用过的内容(通过回到缓冲区中的较早位置,这是“mark”/“reset”所做的)。 何时使用read()
逐字节以及何时使用read(byte[])
字节数组。因为我认为阅读数组总是更好。那你能举个例子在哪里使用它们吗?【参考方案4】:
BufferedReader 从指定的流中读取几个字符并将其存储在缓冲区中。这使得输入更快。
InputStreamReader 只从指定流中读取一个字符,其余字符仍保留在流中。
例子:
class NewClass
public static void main(String args[]) throws IOException
BufferedReader isr = new BufferedReader(new InputStreamReader(System.in));
Scanner sc = new Scanner(System.in);
System.out.println("B.R. - "+(char)isr.read());
System.out.println("Scanner - " + sc.nextLine());
执行isr.read()语句时,我输入了“hello”,屏幕上打印出了“hello”的字符“h”。如果这是 InputStreamReader,那么剩余的字符“ello”将保留在 System.in 流中,并且 sc.nextLine() 将打印它们。但在这种情况下,它不会发生,因为 BufferedReader 从 System.in 流中读取所有“hello”字符并将它们存储在自己的个人缓冲区中,因此当 sc.nextLine() 为执行。
代码:
class NewClass
public static void main(String args[]) throws IOException
InputStreamReader isr = new InputStreamReader(System.in);
Scanner sc = new Scanner(System.in);
System.out.println("I.S.R. - "+(char)isr.read());
System.out.println("Scanner - " + sc.nextLine());
在这种情况下,InputStreamReader 只读取一个字符作为“hello”输入,剩余的“ello”仍然保留在 System.in 流中,这些字符由 sc.nextLine() 打印;
结论:
BufferedReader 从输入流中读取几个字符(即使我们只需要一个字符,它也会读取更多)并将它们存储在缓冲区中。这就是它被称为 BufferedReader 的原因。我无法弄清楚它一口气读了多少个字符。当我对此答案进行测试时,它从 3 到 10 不等。
InputStreamReader 仅从输入流中读取一个字符,其余字符仍保留在流中。在这种情况下没有中间缓冲区。
当一个或多个线程或对象想要从 System.in 中读取字符时,应使用 InputStreamReader,因为它只读取一个字符,其余字符可供其他对象或线程使用。
BufferedReader 速度很快,因为它维护一个缓冲区,并且与从磁盘/标准输入中检索数据相比,从缓冲区中检索数据总是更快。
【讨论】:
当我在我的 IDE (Intellij) 中运行您的示例时,B.R 和 I.S.R 都返回一个字符“h”并且扫描仪都不执行,除非我输入另一行(或输入“Enter”)。但是,根据您的解释,对于后一个示例,代码“Scanner sc = new Scanner(System.in);”应该自动执行并且相应的打印结果应该是“Scanner - e”;你知道为什么会有区别吗?谢谢! @JacquelineP。可能是因为对于 InputStreamReader,内部可能会维护一个很小的缓冲区,所以当您键入“hello”时,会从流中读取整个字符串并存储在内部缓冲区中,因此 Scanner 正在等待输入其他一些输入因为现在流是空的。所以,试着输入一个很长的可能 50 个或更多字符的字符串然后查看,或者尝试输入一个带有空格的大句子然后查看结果。 大概,这是最好的解释。对于那些对没有如@ChaitanyaVaishampyan 解释的那样获得所需结果感到困惑的人来说,在这两种情况下都输入一个非常大的字符串。在第一种情况下,您将看到当缓冲区已满时,扫描仪对象将打印大字符串中的所有剩余字符。对于第二种情况,大字符串的第一个字符将由 InputStreamReader 对象打印,而从第二个字符到结尾将由扫描仪对象打印。 这是一个没有解释书籍和谷歌的答案。但是,它通过示例将概念解释到了核心。谢谢你。【参考方案5】:BufferedReader 从输入流中读取几个字符并将它们存储在缓冲区中。
InputStreamReader 仅从输入流中读取一个字符,其余字符仍保留在流中,因此在这种情况下没有缓冲区。
【讨论】:
【参考方案6】:BufferedReader 是 Java 中的一个类,它从字符输入流中读取文本,缓冲字符,以提供字符、行和数组的有效读取。可以指定缓冲区大小。如果不是,则可以使用预定义的默认大小。
通常,由 Reader 发出的每个读取请求都会导致对底层字符或字节流发出相应的读取请求。因此,最好将 BufferedReader 包裹在 read() 操作可能成本很高的任何 Reader 周围,例如 FileReaders 和 InputStreamReaders。例如,
FileReader reader = new FileReader(“MyFile.txt”); BufferedReader bufferedReader = new BufferedReader(reader);
将缓冲来自指定文件的输入。如果没有缓冲,每次调用 read() 或 readLine() 都可能导致从文件中读取字节,转换为字符,然后返回,这可能非常低效。
来源:https://medium.com/@isaacjumba/why-use-bufferedreader-and-bufferedwriter-classses-in-java-39074ee1a966
【讨论】:
【参考方案7】:据我了解,与 InputStreamReader 相比,BufferedReader 将数据从字节转换为字符所需的时间更少。因此我们更喜欢 BufferedReader 以获得更好的性能
【讨论】:
以上是关于Java 的 BufferedReader 和 InputStreamReader 类有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Java 中使用 BufferedReader 反转希腊字母?
Java 的 BufferedReader 和 InputStreamReader 类有啥区别?
Java - 使用 BufferedWriter 和 BufferedReader,[重复]
Java:BufferedReader 的 readLine 方法的效率和可能的替代方案