Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/345.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java I/O中的缓冲链和装饰原理_Java_Io_Buffer - Fatal编程技术网

Java I/O中的缓冲链和装饰原理

Java I/O中的缓冲链和装饰原理,java,io,buffer,Java,Io,Buffer,是的,我知道缓冲区是什么。但请注意: BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt")); 缓冲在这里实际上是如何工作的?在我看来,我们是在FileWriter缓冲区中缓冲数据,而不是在BufferedWriter缓冲区中。因为当BufferedWriter的缓冲区满时,它会将其发送到FileWriter缓冲区,并负责写入数据 我错过什么了吗?在我看来:看起来我们正在从

是的,我知道缓冲区是什么。但请注意:

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"));
缓冲在这里实际上是如何工作的?在我看来,我们是在FileWriter缓冲区中缓冲数据,而不是在BufferedWriter缓冲区中。因为当BufferedWriter的缓冲区满时,它会将其发送到FileWriter缓冲区,并负责写入数据

我错过什么了吗?在我看来:看起来我们正在从一个大的容器到一个小的容器啜饮着水。所以我们最后从较小的那个里倒水

类似的例子如下:

Scanner scanner = new BufferedReader(new FileReader("file.txt"));
scanner.nextLine();
我到处都看到过。实际上,我们最终是逐行从扫描仪中读取数据,而不是从缓冲区及其8k容量中读取数据。那么这里的缓冲点是什么呢?我们从文件中逐行读取,而不是一次读取整个缓冲区。bufferedReader redundand在这里吗


如果有人能很好地解释这一点,我已经挣扎了很长时间。

读取和写入数据的低级系统调用经过优化,可以立即传输较大的数据块。缓冲让您可以利用这一点。当您写入单个字符或短字符串时,它们都累积在缓冲区中,并在缓冲区已满时作为一个大数据块写入。读取数据时,读取函数请求填充一个大的缓冲区,然后从该缓冲区返回数据

您是对的,在其他缓冲流中包装缓冲流是毫无意义的:充其量它什么也得不到,充其量它会增加开销,因为数据是不必要地从一个缓冲区复制到下一个缓冲区的。最靠近数据源的缓冲区最重要

另一方面,API规范中没有说明FileWriter和FileReader具有缓冲区。事实上,它建议您和:

<>对于最高效率,考虑在<代码> BuffeDeReDebug < /代码>中包装<代码> OutPosiDraveScript < /代码>,以避免频繁的转换器调用。例如:

Writer out
  = new BufferedWriter(new OutputStreamWriter(System.out));
(FileWriter是OutputStreamWriter的子类)

这在内部是如何工作的? 但是,如果您看看FileWriter是如何实现的,故事会变得复杂,因为FileWriter确实涉及缓冲区。一些细节可能取决于您使用的Java版本。在OpenJDK中,当您创建一个BufferedWriter来装饰FileWriter时,如:

BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("file.txt"));
您正在创建一个对象堆栈,如下所示,其中一个对象包裹下一个对象:

BufferedWriter -> FileWriter -> StreamEncoder -> FileOutputStream
其中是一个内部类,是如何实现的一部分

现在,当您将字符写入
BufferedWriter
实例时,它首先将它们累积到BufferedWriter自己的缓冲区中。内部
FileWriter
在写入足够的数据以填充此缓冲区(或调用
flush()
)之前,不会看到任何数据

BufferedWriter
缓冲区变满时,它只需调用一次即可将缓冲区的内容写入
FileWriter
。这种大数据块的传输是效率的来源:现在FileWriter有一大块数据可以写入文件,而不是单个字符

然后它变得有点复杂:字符必须转换成字节,这样才能写入文件。这是FileWriter将这些数据传递到StreamEncoder的地方

StreamEncoder类使用一次将字符块转换为字节,并将字节累积到自己的缓冲区中。完成后,它将字节作为一个块写入最内层的FileOutputStream。FileOutputStream然后调用操作系统函数写入实际文件

如果您没有使用BufferedWriter怎么办? 如果直接将字符写入FileWriter,它们将传递到StreamnCoder对象,该对象将它们转换为字节并存储在其专用缓冲区中,而不是直接写入FileOutputStream。这样,FileWriter的内部实现为您提供了缓冲的一些好处。但这不是API规范的一部分,所以您不应该依赖它


此外,每次调用
FileWriter.write
都会导致调用CharsetEncoder将字符编码为字节。一次对大块字符进行编码更有效,编写单个字符或短字符串的开销更大。

谢谢,这是一个很好的答案。有一件事我不同意/不理解FileWriter没有缓冲。如果你写了一些东西而没有刷新它,它永远不会写(除非它的缓冲区满了——我想是1kb)。还有一件事:假设FileWriter确实有1kb,bufferedWriter有8kb。如果我要写10kb的数据,Java会发出2个I/O请求(查看更大的缓冲区)还是10个I/O请求(查看底层缓冲区)?FileWriter没有自己的缓冲区-我添加了到源代码的链接,以便您自己查看。FileWriter将数据写入具有8192字节缓冲区的StreamEncoder。如果StreamEncoder缓冲区为1k,而您向file FileWriter写入了10k,您将看到10次1k的写入操作。非常感谢!只有一件事。如果我看错了,请纠正我。所以有一个缓冲区在转换之前缓冲,还有另一个缓冲区在写入之前缓冲,对吗?当然,如果我使用FileWriter,那么当您直接写入FileWriter时,只有一个缓冲区:字节缓冲区,它将字符编码结果累积为字节。当缓冲区变满时,会将其写入输出文件。每次将字符编码为字节的调用都会有一些开销,而批量编码的总开销比1乘1低。默认BufferedWriter缓冲区为8k个字符,而StreamnCoder缓冲区为8k个字节。在重要的边缘情况下,如ASCII文本字符映射到字节1到1,编码8k字符会产生8k字节,因此StreamnCoder只需调用CharsetEncoder一次。在一般情况下,一个字符可以编码为几个字节,编码8k字符的结果不能一次全部放入StreamnCoder缓冲区。在这里