5

組み込み Linux デバイスで Java 1.5 を使用しており、2MB の int 値を含むバイナリ ファイルを読みたいと考えています。(現在は 4 バイトのビッグ エンディアンですが、フォーマットは私が決めることができます)

DataInputStreamvia using ) をBufferedInputStream 使用するdis.readInt()と、これらの 500 000 の呼び出しを読み取るには 17 秒が必要ですが、1 つの大きなバイト バッファーに読み取られるファイルには 5 秒かかります。

そのファイルを 1 つの巨大な int[] にすばやく読み込むにはどうすればよいですか?

読み取りプロセスでは、さらに 512 kb を超えて使用しないでください。

以下のコードnioは、Java io の readInt() アプローチよりも高速ではありません。

    // asume I already know that there are now 500 000 int to read:
    int numInts = 500000;
    // here I want the result into
    int[] result = new int[numInts];
    int cnt = 0;

    RandomAccessFile aFile = new RandomAccessFile("filename", "r");
    FileChannel inChannel = aFile.getChannel();

    ByteBuffer buf = ByteBuffer.allocate(512 * 1024);

    int bytesRead = inChannel.read(buf); //read into buffer.

    while (bytesRead != -1) {

      buf.flip();  //make buffer ready for get()

      while(buf.hasRemaining() && cnt < numInts){
       // probably slow here since called 500 000 times
          result[cnt] = buf.getInt();
          cnt++;
      }

      buf.clear(); //make buffer ready for writing
      bytesRead = inChannel.read(buf);
    }


    aFile.close();
    inChannel.close();

更新: 回答の評価:

PC では、IntBuffer アプローチを使用したメモリ マップが私の設定で最速でした。
組み込みデバイスでは、jit を使用しない場合、java.io DataiInputStream.readInt() は少し高速でした (17 秒、IntBuffer を使用した MemMap では 20 秒)。

最終的な結論: 大幅な高速化は、アルゴリズムの変更により実現しやすくなります。(初期化用の小さいファイル)

4

3 に答える 3

3

nio パッケージから使用できIntBufferます -> http://docs.oracle.com/javase/6/docs/api/java/nio/IntBuffer.html

int[] intArray = new int[ 5000000 ];

IntBuffer intBuffer = IntBuffer.wrap( intArray );

...

を呼び出して、バッファを埋めますinChannel.read(intBuffer)

バッファがいっぱいにintArrayなると、500000 個の整数が含まれます。

編集

Channels のみがサポートされていることに気付いた後ByteBuffer

// asume I already know that there are now 500 000 int to read:
int numInts = 500000;
// here I want the result into
int[] result = new int[numInts];

// 4 bytes per int, direct buffer
ByteBuffer buf = ByteBuffer.allocateDirect( numInts * 4 );

// BIG_ENDIAN byte order
buf.order( ByteOrder.BIG_ENDIAN );

// Fill in the buffer
while ( buf.hasRemaining( ) )
{
   // Per EJP's suggestion check EOF condition
   if( inChannel.read( buf ) == -1 )
   {
       // Hit EOF
       throw new EOFException( );
   }
}

buf.flip( );

// Create IntBuffer view
IntBuffer intBuffer = buf.asIntBuffer( );

// result will now contain all ints read from file
intBuffer.get( result );
于 2013-04-15T18:20:11.333 に答える
2

シリアライズ/デシリアライズ、DataInputStream と ObjectInputStream を使用してかなり慎重に実験を行いました。両方とも ByteArrayInputStream に基づいて、IO の影響を回避しました。100 万 int の場合、readObject は約 20 ミリ秒、readInt は約 116 ミリ秒でした。100 万 int 配列のシリアライゼーション オーバーヘッドは 27 バイトでした。これは2013年っぽいMacBook Proでした。

そうは言っても、オブジェクトのシリアル化は一種の悪であり、Java プログラムでデータを書き出す必要があります。

于 2014-12-20T06:01:18.023 に答える