我多次使用过流,但我从来没有读过很多关于它们实际工作情况的信息。除了流只是一个比喻之外,我也不太了解它们。流只表示字节序列。我不太了解它们实际上是如何工作的,我想在Java中打开一个文件流与具有向流提供“指针”功能的操作系统进行交互。
基本上我的问题是流如何影响内存消耗。例如,当你有一个输入流并开始从它读取时,你只开始增加读取的字节数的内存消耗?在Java中打开流时,在开始阅读之前,实际上并没有加载完整的文件?如果从一个流中读取并直接写入另一个流,则只增加内存的读取字节数(可能还有缓冲区)?如果你在java中读取字节数组的字节,那么你会增加文件大小的内存消耗?
可能听起来像一个奇怪的问题,但我可能需要一些指导/纠正我的理解。感谢。
答案 0 :(得分:5)
上面的所有答案都是很好的答案,但我不相信他们会回答你关于记忆消耗的原始问题。
在Java中,您可以通过多种方式查看流。首先,您拥有Raw流,它是最低级别的流,并以最小的内存开销与底层操作系统(文件,网络等)交互。其次是缓冲流,可用于包装原始流并添加一些缓冲并显着提高性能。流缓冲为缓冲添加了固定数量的内存开销,可以由您的应用程序设置。不确定默认值是什么,但它可能是最小的,如32K。
第三种类型的流是一个内存流(即ByteArrayInput / Ouput),它们使用尽可能多的内存,并且会根据需要增长,并且在引用计数变为零之前不会丢弃它们的内存(它们不是使用时间更长)。这些流非常有用,但显然会占用大量内存。
最终类型实际上不是流,而是一类称为读者的I / O,它提供了与流之间的数据转换的协助,如上所述。这些流可以在raw上运行。缓冲或内存流,将消耗与正在使用的基础流一样多的内存。
答案 1 :(得分:3)
从InputStream
开始阅读后,几乎没有“强大的内存开销”。用于打开文件的操作系统开销非常小,而在JVM中用于新对象分配的开销很小。如果使用BufferedInputStream
,默认情况下为8KB,也可能会产生很小的开销。
写作的开销很大程度上取决于你写的位置。如果它是FileOutputStream
,则它与上述相同。如果它是ByteArrayOutputStream
,那么在最好的情况下它是(2 *流长度)字节,在最坏的情况下是(3 *流长度)字节。即将InputStream
中的10k字节复制到字节数组中,在最坏的情况下将分配30k字节。
原因是ByteArrayOutputStream
大小在达到限制后增长了2倍,并且在您调用toByteArray()
时也会分配新的缓冲区。