写入OutputStream时测量中间吞吐量[或]为什么write()阻塞,而read()不是?

时间:2012-04-16 17:59:08

标签: java android nio apache-commons java-io

我需要测量上传和下载大文件的中间吞吐量(使用Apache Commons Net API通过FTP)。

下载(没问题)

下载时一切正常,使用如下代码:

InputStream is = ftp.retrieveFileStream(filePath);
byte[] buffer = new byte[256 * 1024];
int read;

while ((read = is.read(buffer, 0, buffer.length)) != -1) {
    Log.v(TAG, "Read = " + read);
}

此处,缓冲区大小为256 KB,正在下载的文件总大小为1 MB。对is.read()的每次单独调用仅返回大约2 KB。在这种情况下,read() 不会阻止,直到缓冲区已满。这使我能够测量中间下载吞吐量。到目前为止一切都很好。

上传:(有问题)

现在来了痛苦。当我分配一个类似大小的缓冲区来写入OutputStream时,对write()的调用会阻塞,直到写入整个256 KB。

为什么只有write()阻止,而read()没有?

所以我尝试使用nio。与Outputstream的write()不同,WritableByteChannel的write()方法返回实际写入的字节数。所以它必须是非阻塞的,对吧?没有这样的运气。此write()也会阻塞,直到写入整个缓冲区。这是代码:

byte[] buffer = new byte[256 * 1024];
new Random.nextBytes(byteArray);

OutputStream os = ftp.storeFileStream(filePath);
WritableByteChannel channel = Channels.newChannel(os);
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
int written = channel.write(byteBuffer);

那么如何在上传阻止时测量中间吞吐量?

一种方法是使用Android的TrafficStats API。但它伴随着自己的一系列挫折。根据文档,这些统计信息可能并非在所有平台上都可用。此外,它还需要处理整数计数器溢出(2GB后)和counter reset bugs on some platforms等场景,以便在3G和Wifi之间切换。

有人能给我一个出路吗?

1 个答案:

答案 0 :(得分:0)

  

为什么只有write()块,而read()不是?

因为这是底层操作系统的行为方式。