0

我正在移植一些目标 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位置 = 0 且长度 = 字节数组长度的实例,byteArray 是从文件中读取的原始字节 [],而 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);  
    }

}
4

2 回答 2

2

在纯 Java 中没有办法神奇地假设一种类型可以变成另一种类型。顺便说一句,您可以使用 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();
}

注意:这不会运行足够长的时间,甚至无法被 JITted 到本机代码。

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);
}

在 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
于 2013-01-23T17:51:31.777 回答
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);
于 2013-01-23T17:51:56.780 回答