1)缓冲流如何在后台工作,它们与普通流有什么不同?使用它们的优势是什么?
2)DataInputStream
也是 Byte 。但它有readLine()
的方法。这里有什么意义?
答案 0 :(得分:8)
来自BufferedInputStream javadoc:
BufferedInputStream将功能添加到另一个输入流 - 即缓冲输入并支持标记和重置方法的功能。创建BufferedInputStream时,会创建一个内部缓冲区数组。当读取或跳过来自流的字节时,内部缓冲区根据需要从包含的输入流中重新填充,一次多个字节。标记操作记住输入流中的一个点,并且重置操作使得从最近的标记操作开始读取的所有字节在从包含的输入流中获取新字节之前被重新读取。
在内部使用缓冲区数组,而不是从底层输入流中单独读取字节,而是读取足够的字节来填充缓冲区。这通常会导致更快的性能,因为底层输入流需要更少的读取。
BufferedOutputStream则相反。
mark()和reset()可以按如下方式使用:
1 BufferedInputStream bis = new BufferedInputStream(is);
2 byte[] b = new byte[4];
3 bis.read(b); // read 4 bytes into b
4 bis.mark(10); // mark the stream at the current position - we can read 10 bytes before the mark point becomes invalid
5 bis.read(b); // read another 4 bytes into b
6 bis.reset(); // resets the position in the stream back to when mark was called
7 bis.read(b); // re-read the same 4 bytes as line 5 into b
更多地解释标记/重置......
BufferInputStream在内部记住缓冲区中的当前位置。当您读取字节时,位置将递增。对标记(10)的调用将保存当前位置。随后的read调用将继续增加当前位置,但调用reset将在调用mark时将当前位置设置回其值。
标记的参数指定在标记位置失效之前调用标记后可以读取的字节数。一旦标记位置无效,您就不能再调用reset来返回它。
例如,如果在第4行中使用了mark(2),则在第6行调用reset()时将抛出IOException,因为标记位置因为我们读取的字节数超过2个而无效。
答案 1 :(得分:8)
缓冲读取器/写入器/ InputStreams / OutputStream以大块读取和写入操作系统以进行优化。在写入器和输出流的情况下,数据被缓冲在内存中,直到有足够的数据来写出大块。在读取器和输入流的情况下,从磁盘/网络/ ...读取大块到缓冲区中,并且从缓冲区完成所有读取,直到缓冲区为空,并且读入新块。
DataInputStream确实是基于字节的。不推荐使用readLine方法。在内部,它从磁盘/网络/ ...逐字节读取字节,直到它收集完整的行。因此,可以通过使用BufferedInputStream作为源来加速此流,以便从内存缓冲区而不是直接从磁盘读取该行的字节。
答案 2 :(得分:4)
对于未缓冲的I / O,每个读取或写入请求都直接传递给操作系统。 Java的缓冲I / O流将数据读写到自己的内存缓冲区(通常是字节数组)。仅当缓冲区为空(执行读取时)或缓冲区已满(执行写入时)时才会调用操作系统。在应用程序中的关键点之后手动刷新缓冲区有时是个好主意。
由于操作系统API调用可能导致磁盘访问,网络活动等,因此这可能非常昂贵。使用缓冲区将本机操作系统I / O批量处理为更大的块通常可以显着提高性能。
答案 3 :(得分:2)
缓冲流以更大的块的形式写入或读取数据 - - nomen est omen - buffering。根据底层流,这可以显着提高性能。
来自java.io.BufferedOutputStream的Javadocs:
通过设置这样的输出流, 应用程序可以将字节写入 没有的基础输出流 必然会打电话给 每个字节的底层系统 写入。
答案 4 :(得分:0)
为了减少这种开销,Java平台实现了缓冲的I / O流。缓冲输入流从称为缓冲区的存储区读取数据;仅当缓冲区为空时才调用本机输入API。类似地,缓冲输出流将数据写入缓冲区,仅当缓冲区已满时才调用本机输出API。