2013-04-15 11 views
5

私は組み込みLinuxデバイスでJava 1.5を使用し、2MBのint値を持つバイナリファイルを読み込みたいとします。 (今ビッグエンディアンは4バイト、私は決めることができ、フォーマット)dis.readInt()を使用してBufferedInputStream経由DataInputStreamを使用してバイナリファイルから膨大な数のintを読み込む最速の方法

)、これらの500回の000のコールが読み17Sが必要ですが、一つの大きなバイトのバッファに読み込まれたファイルには、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()は少し速く(IntBufferとMemMapため17S、20S VS)であった

最終的な結論: 著しい速度アップは、ビア達成することが容易ですアルゴリズムの変更。あなたはNIOパッケージからIntBufferを使用することができます

+0

http://makeprogrammingyourforte.blogspot.in/2012/09/fastestway-to-read-input-in-java.html – Algorithmist

+0

@Algorithmist @あなたのリンクを確認しましたが、テキストから読み込みますファイル – AlexWien

+0

バークレーにはバルクIO JNI拡張機能があります(こちらはhttp://www.cs.berkeley.edu/~bonachea/java/)。私はそれを使用していないが、それは見た目には良いかもしれない。 –

答えて

4

アレクサンダーよりも速いのかどうかわかりませんが、ファイルをマッピングできます。

try (FileInputStream stream = new FileInputStream(filename)) { 
     FileChannel inChannel = stream.getChannel(); 

     ByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size()); 
     int[] result = new int[500000]; 

     buffer.order(ByteOrder.BIG_ENDIAN); 
     IntBuffer intBuffer = buffer.asIntBuffer(); 
     intBuffer.get(result); 
    } 
+0

私は明日お試しいただき、結果を投稿していただきます。 – AlexWien

+1

PC上ではこれが最速の解決策でしたが、JITなしの埋め込みでは20秒かかったので、Java ioはまだまだ高速です。おもしろい... – AlexWien

3

(初期化のためのより小さいファイル) - >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の整数が含まれます。

EDIT

チャンネルのみ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); 
+0

私はすでにそれを試みたが、私は "int bytesRead = inChannel.read(intBuffer);で立ち往生している"これはコンパイルされません、私はinChannel.read()にIntBufferを渡すことはできません、それはbyteBuffer – AlexWien

+0

@AlexWienをexpoectsします。 –

+0

多くのありがとう、今は動作しますが、私のデバイスでは25秒を使用します – AlexWien

2

私はシリアライズ/デシリアライズ、ObjectInputStreamの対DataInputStreamを、IOの影響を避けるためにするByteArrayInputStreamに基づいて両方を使用して、かなり慎重な実験を実行しました。百万の整数の場合、readObjectは約20msec、readIntは約116でした。百万のint配列のシリアル化のオーバーヘッドは27バイトでした。これは2013年のMacBook Pro上にありました。

オブジェクトのシリアライゼーションは悪いことであり、Javaプログラムでデータを書き出す必要があります。

+0

これは面白いです、私はwriteObjectを使用する可能性を考慮していません。 writeObjectは、書き込む前にBits.putInt()を使用してバイト[]を内部的に埋めます。これは単純にwriteInt()を何百回も呼び出すより速いかもしれません。 (java.nioはディスクへのDMAアクセスを使用するため、java.ioよりもPC上で高速です(組み込みデバイスでは使用できません) – AlexWien

関連する問題