你如何决定 InputStream.read() 使用啥字节 [] 大小?

Posted

技术标签:

【中文标题】你如何决定 InputStream.read() 使用啥字节 [] 大小?【英文标题】:How do you decide what byte[] size to use for InputStream.read()?你如何决定 InputStream.read() 使用什么字节 [] 大小? 【发布时间】:2012-02-03 15:48:24 【问题描述】:

当从 InputStreams 中读取数据时,如何决定 byte[] 使用什么大小?

int nRead;
byte[] data = new byte[16384]; // <-- this number is the one I'm wondering about

while ((nRead = is.read(data, 0, data.length)) != -1) 
  ...do something..

什么时候用小号和大号?有什么区别?该数字是否希望以 1024 为增量?如果它是来自网络的 InputStream 与来自磁盘的 InputStream 有区别吗?

非常感谢,我似乎在别处找不到明确的答案。

【问题讨论】:

我想知道 c# 的同样问题。我想这是相同的答案。大概内存占用可以考虑进去(chunck越小,内存占用越小)。另一个因素是输入流的类型...与内存流相比,网络流填充缓冲区需要更长的时间...如果缓冲区较大,您将获得较少的控制。 更大的数据应该加快从快速源读取的速度(更少的迭代),另一方面,在慢源的情况下会浪费空间(速度主要是等待,所以它不会不管你的循环有多快) 【参考方案1】:

我还要说,如果从 InputStream 读取(而不是像 FileChannelSocketChannel 那样从 ReadableByteChannel 读取),你不应该在意,只要你把它包裹起来具有“正确”缓冲区大小的BufferedInputStream:内部缓冲区将为您处理读取操作,因此您可以专注于读取您需要的部分。

在这种情况下,缓冲区大小可能是您正在寻找的,我会将您重定向到@Peter Lawrey's answer:从网络访问数据时为 2-8KB,从硬盘驱动器访问数据时为 32-64KB(a “块”磁盘)。

不过,当从 ByteChannel 读取数据时,您必须通过可以使用该值分配的 ByteBuffer 自己进行缓冲。

【讨论】:

【参考方案2】:

在这种情况下,我总是使用 2 的合理幂,范围在 2K 到 16K 之间。一般来说,不同的 InputStream 会有不同的最优值,但没有简单的方法来确定该值。

为了确定最佳值,您需要更多地了解您正在处理的 InputStream 的确切类型,以及为 InputStream 提供服务的硬件规格等信息。

担心这可能是过早优化的情况。

【讨论】:

【参考方案3】:

这主要取决于您拥有多少内存以及您希望读取多少数据。你不想太频繁地阻塞,所以考虑BenCole的回答;另一方面,如果您的处理速度比实际读取速度慢,您不希望处理一小块数据。

我个人尝试使用库并将选择缓冲区大小的任务交给库作者。在那之后,我保证自己永远不会阅读库代码,因为它让我很生气。

【讨论】:

【参考方案4】:

大多数人使用 2 的幂来表示尺寸。 如果缓冲区至少为 512 字节,则差别不大(

对于网络,最佳大小可以是 2 KB 到 8 KB(底层数据包大小通常高达 ~1.5 KB)对于磁盘访问,最快的大小可以是 8K 到 64 KB。如果您使用 8K 或 16K,则不会有问题。

注意网络下载,您可能会发现您通常不会使用整个缓冲区。对于 99% 的用例来说,浪费几 KB 并没有多大关系。

【讨论】:

关于网络/磁盘之间区别的重要信息!我猜所使用的协议会产生很大的不同(CIFS,NFS,...)。你注意到了吗(例如使用 Java Chonicles ;))wrt 网络?我正要问这样的问题…… @Matthieu 网络通常配置为具有 1536 字节的 MTU,因此如果您以足够快的速度读取流,您将很少看到 2K 缓冲区填充。然而,磁盘子系统往往具有大约 64 K 的本机块大小,因此对于比这大得多的文件,更大的块始终被填充。【参考方案5】:

通过使用InputStream 类中的available() 方法。来自 Javadoc:

返回可以从中读取(或跳过)的字节数 此输入流不会被方法的下一个调用者阻塞 这个输入流。下一个调用者可能是同一个线程或或 另一个线程。

【讨论】:

available() 方法的唯一合理用途是确定调用是否可能阻塞。您应该只关心它是零还是非零。您还应该理解某些实现可能每次都返回零,在这种情况下,您的代码需要注意这一点,然后忽略它。 available() 不保证返回数据的总大小,下一个 read() 将填充的数量,或者特别是任何东西。 当前 javadoc 链接与答案中给出的引用不一致:docs.oracle.com/javase/7/docs/api/java/io/…

以上是关于你如何决定 InputStream.read() 使用啥字节 [] 大小?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Android 上解除对 InputStream.read() 的阻止?

Java 套接字:InputStream.read() 与 BufferedReader.read()

InputStream.read() 返回的 0 是啥意思?如何处理?

为啥 InputStream#read() 返回一个 int 而不是一个字节?

捕获 BluetoothSocket InputStream.read() 超时的线程

java InputStream读取数据问题