Java:有效地将long数组转换为字节数组

时间:2015-04-28 18:32:37

标签: java arrays type-conversion long-integer endianness

我有一个longs数组我要写入磁盘。最有效的磁盘I / O函数采用字节数组,例如:

FileOutputStream.write(byte[] b, int offset, int length)

...所以我想首先将long[]转换为byte[](每个long为8个字节)。我很难找到一个干净的方法来做到这一点。

直接类型转换似乎不允许:

ConversionTest.java:6: inconvertible types
found   : long[]
required: byte[]
    byte[] byteArray = (byte[]) longArray;
                            ^

通过迭代数组很容易进行转换,例如:

ByteBuffer bytes = ByteBuffer.allocate(longArray.length * (Long.SIZE/8));
for( long l: longArray )
{
    bytes.putLong( l );
}
byte[] byteArray = bytes.array();

...然而,这似乎远不如简单地将long []视为一系列字节。

有趣的是,当阅读文件时,它很容易被“阉割”#34;从byte[]到使用Buffers的长期:

LongBuffer longs = ByteBuffer.wrap(byteArray).asLongBuffer();

...但我似乎找不到任何相反方向的功能。

我了解从long转换为byte时会有端点注意事项,但我相信我已经解决了这些问题:我使用上面显示的Buffer框架,默认情况下到大端,不管本机字节顺序。

3 个答案:

答案 0 :(得分:2)

不,没有一种简单的方法可以从long[]转换为byte[]

您最好的选择可能是将FileOutputStream包裹在BufferedOutputStream中,然后为每个byte写出单独的long值(使用按位运算符)。

另一种选择是创建ByteBuffer并将long值放入ByteBuffer,然后将其写入FileChannel。这会为您处理字节顺序转换,但会使缓冲变得更加复杂。

答案 1 :(得分:1)

关于效率,很多细节实际上几乎没有什么区别。到目前为止,硬盘是这里涉及的最慢的部分,并且在将单个字节写入磁盘所需的时间内,您可以将数千甚至数百万字节转换为long。此处的每个性能测试都不会告诉您有关实现的性能的任何信息,而是关于硬盘的性能。有疑问,应该制作专门的基准,比较不同的转换策略,并分别比较不同的写作方法。

假设主要目标是允许方便转换并且不会产生不必要的开销的功能,我想提出以下方法:

可以创建一个足够大小的ByteBuffer,将其视为LongBuffer,使用批量LongBuffer#put(long[])方法(处理必要的字节顺序转换,并将其作为尽管有效,但最后,使用ByteBuffer将原始long(现在填充FileChannel值)写入文件。

遵循这个想法,我认为这种方法很方便,而且(很可能)效率很高:

private static void bulkAndChannel(String fileName, long longArray[]) 
{
    ByteBuffer bytes = 
        ByteBuffer.allocate(longArray.length * Long.BYTES);
    bytes.order(ByteOrder.nativeOrder()).asLongBuffer().put(longArray);
    try (FileOutputStream fos = new FileOutputStream(fileName))
    {
        fos.getChannel().write(bytes);
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
}

(当然,有人可能会争论是否分配“大”缓冲区是最好的想法。但是由于Buffer类的便捷方法,这可以很容易地并且通过合理的努力来修改以写入“块“具有适当大小的数据,对于一个人真的想要写一个巨大的数组并且创建相应的ByteBuffer的内存开销会非常大)

答案 2 :(得分:0)

OP在这里。

想到了一种方法:ByteBuffer.asLongBuffer()返回ByteBufferAsLongBufferB的实例,这是一个将ByteBuffer包装在接口中的类,用于将数据视为long在正确管理字节序的同时。我可以扩展ByteBufferAsLongBufferB,并添加一个方法来返回原始字节缓冲区(protected)。

但这似乎是如此深奥和令人费解,我觉得必须有一个更简单的方法。无论是那种,还是我的方法中的某些东西都是有缺陷的。