BufferedReader 可以读取字节吗?

Posted

技术标签:

【中文标题】BufferedReader 可以读取字节吗?【英文标题】:Can BufferedReader read bytes? 【发布时间】:2014-04-08 14:40:38 【问题描述】:

对不起,如果这个问题是重复的,但我没有得到我想要的答案。

Java 文档这样说

通常,由 Reader 发出的每个读取请求都会导致对底层字符或字节流发出相应的读取请求。因此,建议将 BufferedReader 包装在 read() 操作可能成本高昂的任何 Reader 周围,例如 FileReaders > 和 InputStreamReaders。例如,

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

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

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

    我的第二个问题是 Bufferedreader是否将字符存储在BUFFER中,这一行是什么意思

将缓冲来自指定文件的输入。

    我的第三个问题是这行是什么意思

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

【问题讨论】:

【参考方案1】:

这里有两个问题。

1.缓冲

假设你住在离最近的水源一英里的地方,你每小时喝一杯水。好吧,你不会为了每一杯都走到水边。每天去一次,回家时提着一桶水,足够装满杯子 24 次。

桶是一个缓冲区

想象一下,您的村庄由河流供水。但有时河水干了一个月;其他时候,河流带来的水量太大,村子被洪水淹没。所以你建了一座水坝,在水坝后面有一个水库。水库在雨季充满,在旱季逐渐排空。村子一年四季都有源源不断的水。

水库是一个缓冲区

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

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 的示例很重要。您可能还没有在编程教育中介绍多态性,所以当您这样做时,请记住这一点。这意味着如果你的代码使用了FileReader——但只有符合Reader的部分——那么你可以替换为BufferedReader,它的工作原理是一样的。

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

 Reader reader = new FileReader(file);

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

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

我走了那条弯路,因为所有Readers 不太适合图像。

Reader 有两个read 方法:

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

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

第一个表单看起来好像没问题——毕竟它读取的是整数。事实上,如果您只使用 FileReader,它可能会很好用。

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

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

因此,如果您想读取整数,请使用 InputStream 而不是 ReaderInputStreamint read(byte[] buf, int offset, int length) - 字节从 int 来回转换比从 char 可靠得多。

【讨论】:

感谢您为我写了这么长的文章。我真的很感激,但是其他回答的用户都知道 BufferedReader 是如何工作的,所以我也想增强我对它的工作原理的了解,当然您的文章确实增加了我对 BufferedReader 包裹在 FileReader 上的工作原理 以及 buffer 的了解。 只是想说,很好的答案。 我们很好地解释了@Slim。【参考方案2】:

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

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

所以,回答你的问题:

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

【讨论】:

你能回答这个问题吗[***.com/questions/22199220/…]。如果可以的话请帮忙 我理解了第一点和第三点,但没有得到第二点缓冲阅读器每次读取一行时都会创建一个新缓冲区,你是说缓冲阅读器从缓冲区读取数据,这样可以节省我们的时间? @TruePS - 不,它适用于单个缓冲区。它为来自该缓冲区的读取请求提供服务,当缓冲区变空时,它从底层流/读取器/任何内容中读取一个块来填充缓冲区。是的,这大大提高了性能。 好的,我现在知道了,我最后一件事假设我有一个包含三行的文本文件 test.txt How are you?这意味着Bufferedreader首先读取第一行,即如何将其放入缓冲区,然后读取并将其放入缓冲区,然后您将其放入缓冲区。我对吗?那么缓冲区什么时候会变空?【参考方案3】:

    默认行为是它将转换为字符,但是当您有图像时,您不能有字符数据,而是需要字节数据的像素。所以你不能使用它。

    它正在缓冲,意思是,它正在读取 char 数组中的某个数据块。您可以在代码中看到这种行为:

 public BufferedReader(Reader in) 
               this(in, defaultCharBufferSize);
            

而defaultCharBufferSize如下:

私有静态int defaultCharBufferSize = 8192;

3 Every time you do read operation, it will be reading only one character.

所以简而言之,buffred 的意思是,它会首先读取少量字符数据,这些数据将保存在一个 char 数组中并被处理,然后它会再次读取相同的数据块,直到它到达流的末尾

您可以参考以下内容了解更多

BufferedReader

【讨论】:

假设我有一个包含三行的文本文件 test.txt >How >are >you 这意味着 Bufferedreader 首先读取第一行,即如何将其放入缓冲区,然后读取并将其放入缓冲区,然后你将它放在缓冲区中。我说得对吗?那么缓冲区什么时候会变空? 它将读取 n 个字节或字符数据并存储到一个字符数组中,而不是从 i/o 一次又一次地读取。请记住,每个读取操作都成本更高,并且会对性能产生影响。让我们的文件有 20000 个字节,使用缓冲策略,您将首先读取 512 个字节并将其存储为一个数组,而不是每次读取所有这些 20000 个字符的单个字节。 所以它将读取整整 3 行 How are you and store it into a char array and char array is into a buffer in memory.So bufferedreader将从缓冲区中读取所有数据并显示它并在读取后它清空缓冲区的所有数据。我现在是吗? 读取 char 数组正在缓冲。您可以在我提到的上述链接中看到这一点。 1.它将创建一个具有默认大小的字符数组,并将那么多字符读入该数组,而不是行。然后它将从这个字符数组中形成一行字符串,并在您调用 readLine() 时返回给您。它是如何存储到 char 数组中的,请通过上面链接中的 readLine() 方法。在那里你可以看到这个 char 数组是如何使用的。希望您现在清楚这一点。

以上是关于BufferedReader 可以读取字节吗?的主要内容,如果未能解决你的问题,请参考以下文章

在python中将字节转换为BufferedReader [重复]

Java读取文件-BufferedReader/FileReader/InputStreamReader/FileInputStream的关系和区别

BufferedReader可以在Java中自动关闭吗

BufferInputStreamBufferOutputStreamBufferedReaderBufferedWriterJava代码使用BufferedReader和BufferedWr

BufferedReader,缓冲输入字符流

从 InputStream 读取时,Android Socket BufferedReader readLine() 不起作用