stream Java=下载缓冲区未满?冲洗/缓冲是如何工作的?
我想监控下载数据的进度。我想在传输了一定数量的数据后进行日志记录。我的代码:
int contentLength = 0;
final int bufferSize = 1024*8;
byte[] buffer = new byte[bufferSize];
int length = 0;
while ( (length = bufferedInputStream.read(buffer) ) !=-1 ) {
contentLength = contentLength+length;
if ( (contentLength % (bufferSize*1024*4)) ==0 ) {
logger.debug(contentLength);
}
}
这似乎不起作用。似乎缓冲区并不总是满的,因此用作模的缓冲区大小的倍数不匹配
缓冲区不“满”真的很常见吗?这怎么会发生?bufer被“刷新”的内在逻辑是什么?Java是否等待s的特定时间来接收数据包,然后刷新(如果缓冲区未满)?任何关于它内部工作原理的信息都有助于理解它
(我不需要解决方案,我已经在其他地方实现了它,只是想知道缓冲区从未被完全读取是否很常见?我想知道为什么。)
非常感谢! 延斯
# 1 楼答案
不能保证缓冲区会满。这些是IO的细节。必须使用返回值
read
来确定实际读取了多少数据# 2 楼答案
套接字上的读取操作无法准确填充缓冲区是很常见的。发送者正在刷新不同长度的数据包。然后,它们通过应用程序层、操作系统层和网络层,这些应用程序层、操作系统层和网络层可能会将它们分割开来。典型的结果是部分缓冲区读取
我通常会调整读取缓冲区的大小,以匹配作为最大大小的socket's read buffer,,但我从不指望每次都能填满它
另外,您应该注意,在执行大容量读取(到字节数组中)时,使用
BufferedInputStream
效率很低。这只会增加从一个数组到另一个数组复制数据的开销。它也是上述碎片化的来源之一# 3 楼答案
这实际上取决于实际使用的
InputStream
,归结起来就是“操作系统如何处理read()
调用”在大多数现代操作系统上,基本的
read
调用做同样的事情:它尝试读取所请求的数据,但可能会提前停止当缓冲区大于文件系统的预读缓冲区时,很容易发生这种情况。或者当你从网络连接中读取数据时,只有几个数据包到达
有些设备具有很好的预测性能(从文件系统读取时,如果缓冲区不是很大,则趋向于将其完全填满,从网络读取时,缓冲区会更频繁地被填满一半)。但你不能以这种或那种方式依赖它
所以:是的,这很容易发生
# 4 楼答案
当您可以使用
read(byte[], ...)
API时,流将尝试填充缓冲区中分配的空间。但它并不总能填满它。当然,如果流中的内容用完了,就无法填满整个空间。但也有其他原因。例如,流实现可以使用一些后台线程来获取数据。如果read调用被传递到操作系统,那么它可能一次读取一个数据块。如果流被缓冲,而缓冲区仍然有一些内容,它可能只返回缓冲区中剩余的内容