InputStream、InputStreamReader和BufferedReader在Java中是如何协同工作的?

InputStream、InputStreamReader和BufferedReader在Java中是如何协同工作的?,java,android,inputstream,bufferedreader,inputstreamreader,Java,Android,Inputstream,Bufferedreader,Inputstreamreader,我正在学习Android开发(我一般是编程初学者),学习HTTP网络,并在课程中看到了以下代码: private String readFromStream(InputStream inputStream) throws IOException { StringBuilder output = new StringBuilder(); if (inputStream != null) { InputStreamReader inputStreamReader = new Inpu

我正在学习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();
}
我不太明白InputStream、InputStreamReader和BufferedReader到底做什么。对于BufferedReader,它们都有read()方法和readLine()。为什么我不能只使用InputStream或只添加InputStreamReader?为什么我需要添加BufferedReader?我知道这与效率有关,但我不明白怎么做

我一直在研究并试图解释这一点,但我仍然不知道谁在做什么:

通常,读取器发出的每个读取请求都会导致相应的 对底层字符或字节流发出的读取请求。信息技术 因此,建议将BufferedReader包装在任何读取器周围 其read()操作可能代价高昂,例如文件读取器和 输入流阅读器。比如说,

BufferedReader-in=new-BufferedReader(new-FileReader(“foo.in”)
将缓冲来自指定文件的输入。没有缓冲,每个
调用read()或readLine()可能会导致从中读取字节
文件,转换为字符,然后返回,可以
效率很低

因此,我知道InputStream只能读取一个字节,InputStreamReader只能读取一个字符,BufferedReader只能读取一整行,而且它还可以提高效率,这是我没有得到的。我想更好地了解谁在做什么,以便理解为什么我需要这三个,以及没有其中一个会有什么区别

我在这里和网上的其他地方做了很多研究,似乎没有找到任何我能理解的解释,几乎所有的教程都只是重复文档信息。下面是一些相关的问题,也许可以开始解释这一点,但不要深入,解决我的困惑:。我认为这可能与最后一个问题关于系统调用和返回的解释有关。但我想理解这一切意味着什么

是否BufferedReader的readLine()调用InputStreamReader的read()方法,后者反过来调用InputStream的read()方法?InputStream返回转换为int的字节,一次返回一个字节,InputStreamReader读取足够多的字节以生成一个字符,并将其转换为int,一次返回一个字符,BufferedReader读取足够多的字符以整数表示以组成整行?并将整行作为字符串返回,只返回一次而不是多次?我不知道,我只是想弄清楚事情是怎么回事

非常感谢

这个链接,给出一个很好的解释

Streams、Reader、Writer、BufferedReader、BufferedWriter——这些是您将在Java中处理的术语。Java中提供了一些用于操作输入和输出的类。了解它们之间的关系以及如何使用它们是非常值得的。这篇文章将详细探讨Java和其他相关类中的流。因此,让我们开始:

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


用于处理字节级数据

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

BufferedReader/BufferedWriter
提高性能。要读取的数据将被缓冲到内存中,以便快速访问

虽然这些类用于获取输入,但也只有相应的类用于输出。例如,如果有一个InputStream用于读取字节流,那么OutputStream将有助于写入字节流

输入流
java提供了多种类型的InputStreams。每个连接到不同的数据源,如字节数组、文件等

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

输出流
这有助于将字节写入数据源。对于几乎每一个InputStream,只要有意义,都会有一个对应的OutputStream


更新

什么是缓冲流

这里我引用的是Java文档(附带技术说明):

缓冲流

到目前为止,我们看到的大多数示例都使用无缓冲I/O 每个读或写请求都由底层操作系统直接处理。 这会使程序的效率大大降低,因为每个这样的请求 通常会触发磁盘访问、网络活动或其他操作 这是相对昂贵的

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

有时我在阅读技术文档时会感到毛骨悚然。因此,我在这里引用了更人性化的解释:

通常,磁盘访问比执行的处理慢得多 记忆中;这就是为什么访问磁盘a不是一个好主意 1000次读取1000字节的文件。尽量减少数量 每次访问磁盘时,Java都提供缓冲区,作为 数据仓库

在使用FileInputStream然后BufferedInputStream读取文件时 类BufferedInputStream充当FileInputStream之间的中间人 以及文件本身。它从数据库中读取大量字节
try (InputStreamReader reader =
        new InputStreamReader(stream, StandardCharsets.UTF_8)) {
     ... read text ...
}