Java:有效地将长整型数组转换为字节数组
Java: Efficiently converting an array of longs to an array of bytes
我有一个 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[] 简单地视为一系列字节有效。
有趣的是,当读取文件时,使用缓冲区很容易"cast"从byte[]
到longs:
LongBuffer longs = ByteBuffer.wrap(byteArray).asLongBuffer();
...但我似乎找不到任何相反方向的功能。
我知道从 long
转换为 byte
时需要考虑字节序,但我相信我已经解决了这些问题:我正在使用上面显示的 Buffer 框架,默认为 big endian,无论本机字节顺序如何。
OP在这里。
我已经想到了一种方法:ByteBuffer.asLongBuffer()
return是ByteBufferAsLongBufferB
的实例,class包装接口中的 ByteBuffer,用于在正确管理字节顺序的同时将数据视为 long
s。我 可以 扩展 ByteBufferAsLongBufferB
,并向 return 原始字节缓冲区(即 protected
)添加一个方法。
但这看起来很深奥和令人费解,我觉得一定有更简单的方法。要么,要么我的方法有问题。
不,没有简单的方法可以将 long[]
转换为 byte[]
。
您最好的选择可能是用 BufferedOutputStream
包裹 FileOutputStream
,然后为每个 long
写出单独的 byte
值(使用按位运算符)。
另一种选择是创建 ByteBuffer
并将您的 long
值放入 ByteBuffer
,然后将其写入 FileChannel
。这会为您处理字节顺序转换,但会使缓冲更加复杂。
关于效率,许多细节实际上几乎没有什么不同。到目前为止,硬盘是这里涉及的最慢的部分,在将单个字节写入磁盘所花费的时间中,您可能已经将数千甚至数百万字节转换为长整型。这里的每个性能测试不会告诉你任何关于实现的性能,而是关于硬盘的性能。有疑问,应该做专门的benchmark比较不同的转换策略,分别比较不同的写法。
假设主要目标是一种允许方便转换并且不会强加不必要开销的功能,我想提出以下方法:
可以创建一个足够大小的 ByteBuffer
,将其视为 LongBuffer
,使用批量 LongBuffer#put(long[])
方法(它负责必要的字节序转换,并且这尽可能高效),最后,使用 FileChannel
.[=20= 将原始 ByteBuffer
(现在填充了 long
值)写入文件]
按照这个想法,我认为这种方法很方便,而且(很可能)相当有效:
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();
}
}
(当然,有人可能会争论分配 "large" 缓冲区是否是最好的主意。但是由于 Buffer
类 的便利方法,这可以很容易地和通过合理的努力修改为写入 "chunks" 具有适当大小的数据,对于真正想要写入 huge 数组和创建相应 数组的内存开销的情况=11=] 会太大)
我有一个 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[] 简单地视为一系列字节有效。
有趣的是,当读取文件时,使用缓冲区很容易"cast"从byte[]
到longs:
LongBuffer longs = ByteBuffer.wrap(byteArray).asLongBuffer();
...但我似乎找不到任何相反方向的功能。
我知道从 long
转换为 byte
时需要考虑字节序,但我相信我已经解决了这些问题:我正在使用上面显示的 Buffer 框架,默认为 big endian,无论本机字节顺序如何。
OP在这里。
我已经想到了一种方法:ByteBuffer.asLongBuffer()
return是ByteBufferAsLongBufferB
的实例,class包装接口中的 ByteBuffer,用于在正确管理字节顺序的同时将数据视为 long
s。我 可以 扩展 ByteBufferAsLongBufferB
,并向 return 原始字节缓冲区(即 protected
)添加一个方法。
但这看起来很深奥和令人费解,我觉得一定有更简单的方法。要么,要么我的方法有问题。
不,没有简单的方法可以将 long[]
转换为 byte[]
。
您最好的选择可能是用 BufferedOutputStream
包裹 FileOutputStream
,然后为每个 long
写出单独的 byte
值(使用按位运算符)。
另一种选择是创建 ByteBuffer
并将您的 long
值放入 ByteBuffer
,然后将其写入 FileChannel
。这会为您处理字节顺序转换,但会使缓冲更加复杂。
关于效率,许多细节实际上几乎没有什么不同。到目前为止,硬盘是这里涉及的最慢的部分,在将单个字节写入磁盘所花费的时间中,您可能已经将数千甚至数百万字节转换为长整型。这里的每个性能测试不会告诉你任何关于实现的性能,而是关于硬盘的性能。有疑问,应该做专门的benchmark比较不同的转换策略,分别比较不同的写法。
假设主要目标是一种允许方便转换并且不会强加不必要开销的功能,我想提出以下方法:
可以创建一个足够大小的 ByteBuffer
,将其视为 LongBuffer
,使用批量 LongBuffer#put(long[])
方法(它负责必要的字节序转换,并且这尽可能高效),最后,使用 FileChannel
.[=20= 将原始 ByteBuffer
(现在填充了 long
值)写入文件]
按照这个想法,我认为这种方法很方便,而且(很可能)相当有效:
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();
}
}
(当然,有人可能会争论分配 "large" 缓冲区是否是最好的主意。但是由于 Buffer
类 的便利方法,这可以很容易地和通过合理的努力修改为写入 "chunks" 具有适当大小的数据,对于真正想要写入 huge 数组和创建相应 数组的内存开销的情况=11=] 会太大)