2011-03-06 86 views

回答

3
+0

我无法重现第一个链接的结论,即FileChannel比读取到byte []的FileInputStream相关更快。我怀疑由于他们使用长度为100MB的文件,他们实际上是从操作系统的磁盘缓存而不是硬盘驱动器本身进行基准读取。这可以解释为什么他们的测试意味着250MB/s的带宽,对于磁盘来说相当快。在我对1.5GB文件的测试中,两种方法的吞吐量均达到40MB/s,表明磁盘是瓶颈,而不是CPU。当然,固态硬盘的里程可能会有所不同。 – meriton 2011-03-06 15:01:08

+3

通过让我们知道为什么这些链接可能会有所帮助,您可以提高此答案的质量。仅链接答案并不理想。 – 2015-08-11 14:30:25

22

字节缓冲区是是为基于文件的数据的快速吞吐开发新的IO包(NIO)的一部分。具体来说,Apache是​​一个非常快速的Web服务器(用C语言编写),因为它从磁盘读取字节并将它们直接放到网络上,而无需通过各种缓冲区对其进行洗牌。它通过内存映射文件来完成,Java早期版本没有。随着nio的出现,使用Java编写Web服务器成为可能,这与Apache一样快。当你想要非常快速的文件到网络吞吐量时,你想使用内存映射文件和ByteBuffer。

数据库通常使用内存映射文件,但这种用法在Java中很少有效。在C/C++中,可以加载大量内存并将其转换为所需的类型化数据。由于Java的安全模型,这通常不可行,因为您只能转换为某些本机类型,并且这些转换效率不高。 ByteBuffer在您仅仅将字节作为普通字节数据进行处理时效果最佳 - 一旦您需要将它们转换为对象,其他Java io类通常执行得更好并且更易于使用。

如果你不处理内存映射文件,那么你并不需要打扰ByteBuffer--你通常会使用字节数组。如果您正在尝试构建一个Web服务器,并且基于文件的原始字节数据的吞吐量最快,那么ByteBuffer(特别是MappedByteBuffer)就是您最好的朋友。

+2

这不是Java安全模型的局限。它是JVM体系结构,可防止您将字节转换为键入的数据。 – 2011-03-06 14:25:59

+0

安全模型也影响了ByteBuffer的可用性 - 至少在我现在几年前的测试中。每次调用ByteBuffer类中的某个转换函数时,SecurityManager代码都会被执行,这会降低整个过程的速度。这就是为什么普通的java io函数通常在Java基本类型中读取更快的原因。这与C语言形成了鲜明对比,C语言与内存映射文件的转换相比,使用stdio要快得多。 – JRalph 2011-03-06 14:39:02

+0

查看代码,安全管理器调用只出现在DirectByteBuffer情况下。我认为这是因为该方法使用“不安全”。 – 2011-03-06 15:34:43

20

实际上有很多方法来处理字节。而我认为,这不是一件容易挑选最好的一个:

  • byte[]
  • java.nio.ByteBuffer
  • java.io.ByteArrayOutputStream(与其他流组合)
  • java.util.BitSet

byte[]只是一个原始数组,只包含原始数据。因此,它没有方便的方法来构建或操作内容。

A ByteBuffer更像是一个建造者。它用于创建一个byte[]。与数组不同,它有更方便的辅助方法。 (例如append(byte)方法)。

您可能会说,ByteBuffer确实对byte[]做了什么,StringBuilderString做了什么。但是ByteBuffer课程有一个特定的区别/缺点。就像阵列一样,ByteBuffer具有固定大小。所以,当你实例化它时,你已经必须指定缓冲区的大小。

这就是原因,为什么我经常喜欢使用ByteArrayOutputStream,因为它会自动调整一个,就像一个ArrayList一样。 (它有一个toByteArray()方法)。有时它是实用的,包装在DataOutputStream的好处是,你将有一些额外的方便调用,(例如writeShort(int)如果你需要写2个字节)。

BitSet就派上用场了,当您要执行位级操作。您可以获取/设置个别位,它具有逻辑运算符方法,如xor()。 (toByteArray()方法仅在java 7中引入)。

当然,根据您的需求,您可以将它们全部组合起来以构建您的byte[]