Java =下载缓冲区未完全填充?冲洗/缓冲如何工作?

时间:2011-08-02 15:57:54

标签: java stream io buffer

我想监控下载数据的进度。我希望在传输了一定数量的数据后进行记录。我的代码:

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);
    }   
}

这似乎不起作用。似乎缓冲区并不总是满的,因此用作模数的buffersize的倍数不匹配。

缓冲区不是“满”这真的很常见吗?怎么会发生这种情况?缓冲器被“刷新”的内部逻辑是什么? Java是否等待特定时间接收数据包然后刷新(如果缓冲区未满)?任何有关内部工作原理的信息都非常适合理解它。

(我不需要解决方案,我已经实现了其他方法,只是想知道缓冲区永远不会完全读取是否常见?并且很想知道原因。)

非常感谢! 延

4 个答案:

答案 0 :(得分:1)

套接字上的读操作不会完全填充缓冲区是很常见的。发件人正在刷新各种长度的数据包。然后,它们会传递可能会破坏它们的应用程序,操作系统和网络层。典型的结果是部分缓冲读取。

我通常调整读取缓冲区的大小以匹配作为最大大小的socket's read buffer,,但我从不依赖它每次都填充。

此外,您应该注意,在执行批量读取(进入字节数组)时使用BufferedInputStream是低效的。它只是增加了将数据从数组复制到数组的开销。它也是上面提到的碎片来源之一。

答案 1 :(得分:0)

无法保证缓冲区已满。这些是IO的细节。您必须使用read的返回值来确定实际读取的数据量。

答案 2 :(得分:0)

当你可以使用read(byte[], ...) API时,流将尝试填充缓冲区中的已分配空间。但它并不总能填补它。当然,如果流中的内容用完,则无法填满整个空间。但也有其他原因。例如,流实现可以使用一些后台线程来获取数据。如果将读取调用传递给操作系统,则它可以一次读取一个数据块。如果流被缓冲,并且缓冲区仍然有一些内容,它可能只返回缓冲区中剩余的内容。

答案 3 :(得分:0)

这实际上取决于您使用的实际InputStream,并归结为“操作系统如何处理read()来电”。

在大多数现代操作系统上,基本read调用都做同样的事情:它尝试读取所请求的数据,但可能会提前停止。

当缓冲区大于文件系统的预读缓冲区时,很容易发生这种情况。或者,当您从网络连接中读取数据时,只有少量数据包已经到达。

某些设备具有非常预测的行为(从文件系统中读取趋势以完全填充提供的缓冲区,如果它不是很大,从网络读取会使其更频繁地填充一半)。但你不能以这种或那种方式依赖它。

所以:是的,它很容易发生。