从字节数组创建列表

时间:2013-01-23 17:44:41

标签: java android objective-c

我正在移植一些Objective C代码。

我需要创建一个列表(我将使用任何类型的列表,无论有意义)对象。该课程如下:

class Foo{
    double fooValue1;
    double fooValue2;
    double fooValue3;
    double fooValue4;
}

我正在将二进制文件读入字节数组,该数组工作正常。字节数组是一个列表 4次双打。因此,如果文件中有100个Foo实例,则字节数组有3200个字节。即4 * 8 * 100。

在Objective C中,变量被声明为指向Foo类型数组的指针。通过简单地复制字节来加载该数组是非常快的。这样做的陈述是:

[byteArray getBytes:fooData range:range]

其中range是NSRange实例,其中location = 0,length =字节数组的长度,byteArray是从文件读取的原始byte [],fooData是指向目标数组的指针。

目前,我循环遍历字节数组,为每32个字节创建一个新的Foo实例,然后通过将每个8字节转换为双精度来分配字段。对于数千个对象,这很慢。

我的目标是API 8,因此我无法使用Arrays.copyOf,但如果它提供了一个很好的解决方案,我会考虑更改目标。

问题是;有没有办法以与Objective C类似的“一种语句”方式创建列表?

由于

[编辑]这是我根据彼得的答案使用的最终代码。我应该补充说,该文件实际上包含一个列表,用标题分隔。解析文件的结果是一个字节数组的数组。

ArrayList<SCGisPointData> pointData = new ArrayList<SCGisPointData>();
SCGisPointData thisPointdata;

for (byte[] ring : linearRings) {

    DoubleBuffer buffer = ByteBuffer.wrap(ring).order(ByteOrder.nativeOrder()).asDoubleBuffer().asReadOnlyBuffer();

    thisPointdata= new SCGisPointData ();

    while (buffer.hasRemaining()) {
        thisPointdata = new SCGisPointData();
        thisPointdata.longitude = buffer.get();
        thisPointdata.latitude = buffer.get();
        thisPointdata.sinLatitude = buffer.get();
        thisPointdata.cosLatitude = buffer.get();
        pointData.add(thisPointdata);  
    }

}

2 个答案:

答案 0 :(得分:2)

纯Java中没有办法神奇地假设一种类型可以变成另一种类型。 BTW您可以使用Unsafe在HotSpot中执行此操作,但我不相信您可以在Android中使用它,这可能是最好的。

您可以使用带有本机字节顺序的直接ByteBuffer来加速转换。这样可以最大限度地降低开销,但在Android中并不像在HotSpot中那么快(因为后者可以将这些转化为内在方法)

我想花多长时间作为估计

// or use a MappedByteBuffer from a file
ByteBuffer bb = ByteBuffer.allocateDirect(3200).order(ByteOrder.nativeOrder());
while(bb.remaining() > 0) {
   float f= bb.getFloat();
}

注意:这将无法运行足够长的时间甚至可以JIT到本机代码。

ByteBuffer bb = ByteBuffer.allocateDirect(3200).order(ByteOrder.nativeOrder());
for (int i = 0; i < 12; i++) {
    long start = System.nanoTime();
    bb.clear(); // simulate we have 3200 bytes to read.
    int count = 0;
    while (bb.remaining() > 0) {
        float f = bb.getFloat();
        count++;
    }
    long time = System.nanoTime() - start;
    System.out.printf("Took %,d micro-seconds to read %,d float values%n", time / 1000, count);
}

on HotSpot Java 7打印

Took 960 micro-seconds to read 800 float values
Took 141 micro-seconds to read 800 float values
Took 99 micro-seconds to read 800 float values
Took 101 micro-seconds to read 800 float values
Took 100 micro-seconds to read 800 float values
Took 102 micro-seconds to read 800 float values
Took 115 micro-seconds to read 800 float values
Took 127 micro-seconds to read 800 float values
Took 108 micro-seconds to read 800 float values
Took 79 micro-seconds to read 800 float values
Took 78 micro-seconds to read 800 float values
Took 79 micro-seconds to read 800 float values

答案 1 :(得分:1)

看看MappedByteBuffer。可在Android上使用,并允许您:

  • 将文件映射为字节缓冲区
  • 直接从所述缓冲区读取双值。

您必须小心选择正确的字句。下面是一些示例代码(请注意,API会将字节缓冲区“转换”为双缓冲区,并且您可以一次性从缓冲区中检索多个双精度段):

final String fileName = "/some/path/data.txt";
final MappedByteBuffer byteBuffer = new FileInputStream(fileName)
    .getChannel()
    .map(MapMode.READ_ONLY, 0, 3200);
final DoubleBuffer doubleBuffer = byteBuffer.asDoubleBuffer();

double[] swap = new double[4];
doubleBuffer.get(swap);