0

Objective C コードをいくつか移植しています。

オブジェクトのリストを作成する必要があります (意味のあるものであれば、どのような種類のリストも使用します)。クラスは次のようになります。

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

正常に動作するバイト配列にバイナリ ファイルを読み込んでいます。バイト配列は、4 つの double のリストです。したがって、ファイルに Foo のインスタンスが 100 個ある場合、バイト配列は 3200 バイトになります。つまり、4 * 8 * 100 です。

Objective C では、変数は Foo 型の配列へのポインタとして宣言されます。バイトをコピーするだけでその配列をロードするのは非常に高速です。これを行うステートメントは次のとおりです。

[byteArray getBytes:fooData range:range]

ここで、range はNSRangeロケーション = 0 および長さ = バイト配列の長さのインスタンスであり、byteArray はファイルから読み取られた生の byte[] であり、fooData はターゲット配列へのポインターです。

現時点では、バイト配列をループして、32 バイトごとに Foo の新しいインスタンスを作成し、8 バイトごとに double に変換してフィールドを割り当てています。何千ものオブジェクトの場合、これは遅くなります。

私は API 8 をターゲットにしているArrays.copyOfので利用できませんが、それが良い解決策を提供する場合は、ターゲットを変更することを検討します。

質問は; Objective C と同様の「1 つのステートメント」の方法でリストを作成する方法はありますか?

ありがとう

[編集]ピーターの答えに基づいて使用した最終的なコードは次のとおりです。ファイルには、ヘッダーで区切られたリストのリストが実際に含まれていることを付け加えておきます。ファイルを解析した結果は、バイト配列の配列です。

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

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

注: これは、ネイティブ コードに 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);
}

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 で利用可能で、次のことができます。

  • ファイルをバイトのバッファーとしてマップする
  • 上記のバッファから double 値を直接読み取ります。

適切なエンディアンを選択するように注意する必要があります。サンプル コードを次に示します (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 に答える