InputStream,InputStreamReader和BufferedReader如何在Java中协同工作?

sch*_*v09 5 java android inputstream bufferedreader inputstreamreader

我正在学习Android开发(我是一般的编程初学者)并学习HTTP网络,并在课程中看到了这段代码:

private String readFromStream(InputStream inputStream) throws IOException {
  StringBuilder output = new StringBuilder();
  if (inputStream != null) {
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
    BufferedReader reader = new BufferedReader(inputStreamReader);
    String line = reader.readLine();
    while (line != null) {
      output.append(line);
      line = reader.readLine();
    }
  }
  return output.toString();
}
Run Code Online (Sandbox Code Playgroud)

我不完全理解InputStream,InputStreamReader和BufferedReader的作用.所有这些都有一个read()方法,并且在BufferedReader的情况下也有readLine().为什么我不能只使用InputStream或只添加InputStreamReader?为什么我需要添加BufferedReader?我知道这与效率有关,但我不明白如何.

我一直在研究,BufferedReader文档试图解释这个,但我仍然不知道谁在做什么:

通常,由Reader构成的每个读取请求都会导致相应的读取请求由基础字符或字节流构成.因此,建议将BufferedReader包装在任何read()操作可能代价高昂的Reader上,例如FileReaders和InputStreamReaders.例如,

BufferedReader in = new BufferedReader(new FileReader("foo.in")); 将缓冲指定文件的输入.如果没有缓冲,read()或readLine()的每次调用都可能导致从文件中读取字节,转换为字符,然后返回,这可能是非常低效的.

所以,据我所知,InputStream只能读取一个字节,InputStreamReader只能读取一个字符,而BufferedReader只能读取整行,并且它还可以解决效率问题,这是我无法得到的.我想更好地了解谁在做什么,以便理解为什么我需要他们所有这三个以及没有他们之一的差别.

我在这里和网上的其他地方进行了很多研究,似乎没有找到任何关于我可以理解的解释,几乎所有教程都只重复文档信息.以下是一些相关的问题,可能会开始解释这一点,但不要深入解决我的困惑:Q1,Q2,Q3,Q4.我认为这可能与最后一个问题关于系统调用和返回的解释有关.但我想了解这一切的含义.

可能是BufferedReader的readLine()调用了InputStreamReader的read()方法,而该方法又调用了InputStream的read()方法?并且InputStream返回转换为int的字节,一次返回一个字节,InputStreamReader读取足够的这些字符以生成单个字符并将其转换为int并一次返回一个字符,并且BufferedReader读取足够的这些字符用整数表示整数?并将整行作为String返回,只返回一次而不是几次?我不知道,我只是想弄清楚事情是如何运作的.

非常感谢提前!

ישו*_*ותך 16

这个Streams在Java概念和用法链接中给出了非常好的解释.

这个

Streams,Readers,Writers,BufferedReader,BufferedWriter - 这些是您将在Java中处理的术语.Java中提供了用于输入和输出的类.值得了解这些是如何相关以及如何使用它们.本文将详细探讨Java中的Streams和其他相关类.那么让我们开始吧:

让我们在高层次中定义每一个,然后深入挖掘.


用于处理字节级数据

读/写器
用于处理字符级别.它还支持各种字符编码.

BufferedReader/BufferedWriter
提高性能.要读取的数据将缓冲到存储器中以便快速访问.

虽然这些是用于输入,但是输出也只存在相应的类.例如,如果有一个InputStream用于读取字节流,而OutputStream将帮助写入字节流.

InputStreams
java提供了许多类型的InputStreams.每个都连接到不同的数据源,如字节数组,文件等.

例如,FileInputStream连接到文件数据源,可用于从File读取字节.而ByteArrayInputStream可用于将字节数组视为输入流.

OutputStream
这有助于将字节写入数据源.几乎每个InputStream都有一个相应的OutputStream,只要它有意义.


UPDATE

什么是缓冲流?

这里我引用Buffered Streams,Java文档(有技术说明):

缓冲流

到目前为止,我们看到的大多数示例都使用无缓冲的I/O. 这意味着每个读取或写入请求都由底层操作系统直接处理.这可以使程序效率低得多,因为每个这样的请求经常触发磁盘访问,网络活动或一些相对昂贵的其他操作.

为了减少这种开销,Java平台实现了缓冲的I/O流.缓冲输入流从称为缓冲区的存储区读取数据; 仅当缓冲区为空时才调用本机输入API.类似地,缓冲输出流将数据写入缓冲区,并且仅在缓冲区已满时才调用本机输出API.

有时我会丢失头发阅读技术文档.所以,在这里我引用了更加人性化的解释https://yfain.github.io/Java4Kids/:

通常,磁盘访问比在内存中执行的处理慢得多; 这就是为什么访问磁盘一千次来读取1000字节的文件并不是一个好主意.为了最大限度地减少访问磁盘的次数,Java提供了缓冲区,用作数据存储库.

在此输入图像描述

在使用FileInputStream和BufferedInputStream读取File时,类BufferedInputStream充当FileInputStream和文件本身之间的中间人.它一次性从文件中读取大块字节到内存(缓冲区),然后FileInputStream对象从那里读取单个字节,这是快速的内存到内存操作.BufferedOutputStream与FileOutputStream类的工作方式类似.

这里的主要思想是最小化磁盘访问.缓冲流不会改变原始流的类型 - 它们只会使读取更有效.程序执行流链接(或流管道)以连接流,就像管道连接在管道中一样.

  • 这是一个很好的答案.我只想强调Java COULD刚刚提供了一个非常简单的方法,如:String text = new File("data.txt").getText()来读取所有文本.事实上,Java 8确实提供了类似的东西,但一般来说,Java只是为您提供了各个部分,并允许您以您喜欢的任何方式将它们组合在一起(更接近Python提供解决问题的单一方法的方法,而不是Ruby的"使共同点"事情容易和罕见的可能" - 这往往导致多种方式来解决问题.) (3认同)
  • 伟大的更新,@ישו אוהב אותך!谢谢,我只想再添加一件事,关于这 3 个类是如何协同工作的。在进一步阅读和浏览 OpenJDK 源代码后,在较高的层次上会发生这种情况:BufferedReader 负责维护和填充字符数组,它的 read() 或 readLine() 方法将从这里获取字符。它将通过调用 InputStreamReader 的 read(char[], int, int) 方法来填充。InputStreamReader 与一个StreamDecoder 相关联,当它的read(char[], int, int) 被调用时,它会调用StreamDecoder 的read(char[], int, int)。(1/2) (2认同)
  • (2/2) 这最终会调用底层 InputStream 的 read(byte[], int, int) 方法。这实际上重复调用它的 read() 方法。因此,使用 BufferedReader 的好处是我们将通过自动化从底层 InputStream 一次获取多个字节的过程来减少 OS 调用,而不是进行每次都会进行 OS 调用的单独 read() 调用。这将使我们的计划影响较小。主要来源:http://tutorials.jenkov.com/java-io/bufferedreader.html、http://www.quepublishing.com/articles/article.aspx?p=26067、http://hg.openjdk.java 。网 (2认同)