BufferedReader 可以读取字节吗?

2022-09-03 13:51:44

很抱歉,如果这个问题是一个重复,但我没有得到我正在寻找的答案。

Java文档是这样说的

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

BufferedReader in = new BufferedReader(new FileReader("foo.in"));

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

  1. 我的第一个问题是如果 bufferedReader 可以读取字节,那么为什么我们不能使用 bufferedreader 处理以字节为单位的图像。

  2. 我的第二个问题是Bufferedreader 是否在 BUFFER 中存储字符,以及此行的含义是什么

将缓冲指定文件中的输入。

  1. 我的第三个问题是这句话的含义是什么

通常,对 Reader 发出的每个读取请求都会导致相应的读取请求>由基础字符或字节流构成。


答案 1

这里有两个问题。

1. 缓冲

想象一下,你住在离你最近的水源一英里的地方,每小时喝一杯水。好吧,你不会为每杯都走到水边。每天去一次,回家时要带上一个装满足够水的水,可以装满杯子24次。

存储桶是缓冲区

想象一下,你的村庄由一条河供水。但有时河水干涸一个月;其他时候,河流带来了如此多的水,以至于村庄被洪水淹没。所以你建了一座大坝,大坝后面有一个水库。水库在雨季填满,在旱季逐渐排空。该村全年水源不断。

水库是一个缓冲区

计算中的数据流类似于这两种方案。例如,您可以在单个操作系统系统调用中从文件系统中获取几千字节的数据,但是如果要一次处理一个字符,则需要类似于存储库的东西。

BufferedReader包含另一个Reader(例如FileReader),它是河流 - 以及一个字节数组,这是水库。每次你从中阅读时,它都会做这样的事情:

 if there are not enough bytes in the "reservoir" to fulfil this request
      top up the "reservoir" by reading from the underlying Reader
 endif
 return some bytes from the "reservoir".

但是,当您使用BufferedReader时,您不需要知道它是如何工作的,只需要知道它是如何工作的。

2. 图像适用性

重要的是要了解 BufferedReader 和 FileReader 是 Reader 的示例。你可能还没有在你的编程教育中涵盖多态性,所以当你这样做的时候,记住这一点。这意味着,如果你有代码使用 - 但只有符合它的方面 - 那么你可以替换a,它将工作相同。FileReaderReaderBufferedReader

将变量声明为最通用的类是一个好习惯:

 Reader reader = new FileReader(file);

...因为这将是您需要添加缓冲的唯一更改:

 Reader reader = new BufferedReader(new FileReader(file));

我绕道而行,因为这些都是不太适合图像的。Reader

Reader有两种方法:read

 int read(); // returns one character, cast to an int
 int read(char[] block); // reads into block, returns how many chars it read

第二种形式不适合图像,因为它肯定读的是字符,而不是整数。

第一种形式看起来好像没问题 - 毕竟,它读的是ints。事实上,如果您只使用FileReader,它可能会很好地工作。

但是,请考虑一下包裹在FileReader周围的缓冲阅读器将如何工作。第一次调用 BufferedReader.read() 时,它将调用 FileReader.read(buffer) 来填充其缓冲区。然后,它将缓冲区的第一个转换回 int,并返回该。char

特别是当您将多字节字符集带入图片时,这可能会导致问题。

因此,如果要读取整数,请不要使用 。 有 - 字节比字符更可靠地从int来回转换。InputStreamReaderInputStreamint read(byte[] buf, int offset, int length)


答案 2

Java中的读取器(和编写器)是用于处理文本(字符)流的专用类 - 行的概念在任何其他类型的流中都没有意义。

对于一般的IO等效物,请查看BufferedInputStream

所以,要回答你的问题:

  1. 虽然读取器最终会读取字节,但它会将它们转换为字符。它不打算读取其他任何内容(如图像) - 为此使用InputStream系列类
  2. 缓冲读取器将从底层流(可能是文件、套接字或其他任何内容)中读取大量数据块到内存中的缓冲区,然后从此缓冲区提供读取请求,直到缓冲区被清空。这种每次读取大块而不是小卡盘的行为可以提高性能。
  3. 这意味着,如果您将读取器包装在缓冲读取器中,那么每次要读取单个字符时,它将访问disk.network以获取所需的单个字符。在如此小的块中执行 I/O 通常对性能非常糟糕。

推荐