たとえば、25 GBの大きなテキストファイルを読み取る必要があり、このファイルを15〜20分以内に処理する必要があります。このファイルには、複数のヘッダーセクションとフッターセクションがあります。
CSplitでこのファイルをヘッダーに基づいて分割しようとしましたが、ヘッダーに基づいていくつかのファイルに分割するのに約24〜25分かかり、まったく受け入れられません。
BufferReader
とBufferWiter
をFileReader
とFileWriter
と一緒に使用して、順次読み取りと書き込みを試みました。 27分以上かかります。繰り返しますが、それは受け入れられません。
各ヘッダーの開始インデックスを取得し、複数のスレッドを実行してRandomAccessFile
を使用して特定の場所からファイルを読み取るなど、別のアプローチを試しました。しかし、これには運がありません。
どうすれば要件を達成できますか?
重複の可能性:
データをより高速に処理するには、大きなバッファー読み取りサイズ(たとえば、2MBではなく20MB)を使用してみてください。また、速度と文字変換が遅いため、BufferedReaderを使用しないでください。
この質問は以前に尋ねられました: Javaで大きなファイルを読む
IOが速度を低下させているのではなく、処理が遅いと思われるため、処理なしでIOが十分に高速であることを確認する必要があります。ハードドライブから80MB/s、SSDドライブから最大400 MB/sを取得します。これは、1秒で全体を読み取ることができることを意味します。
以下を試してください。これは最速ではありませんが、最も簡単です。
long start = System.nanoTime();
byte[] bytes = new byte[32*1024];
FileInputStream fis = new FileInputStream(fileName);
int len;
while((len = fis.read(bytes)) > 0);
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds%n", time/1e9);
少なくとも50MB/sを取得していることがわからない限り、ハードウェアに問題があります。
Java.nio
を使用して、オペレーティングシステムの機能をより有効に活用してみてください。データを(文字列などに)コピーすることは避けてください。ただし、offsetsを使用して作業してください。 Java.nioクラスには、データをJavaレイヤーにまったくプルせずに(少なくともLinuxでは)1つのバッファーから別のバッファーにデータを転送するメソッドさえあると思いますが、それは本質的に変換されますオペレーティングシステムコールに。
最近の多くのWebサーバーでは、この手法が静的データを提供できるパフォーマンスの鍵となっています。基本的に、メインメモリへの重複を避けるために、オペレーティングシステムに可能な限り委任します。
これを強調しておきます。25GBのバイトバッファをシークするだけで、Java文字列(文字セットのエンコード/デコードとコピーが必要になる場合があります)に変換するよりもはるかに高速です)。とメモリ管理が役立ちます。
プラットフォームが適切な場合は、シェルアウトして、catとsedの組み合わせを呼び出すことをお勧めします。そうでない場合でも、コマンドラインからシェルアウトしてPerlを使用することをお勧めします。絶対にJava実際の処理を行う必要がある場合は、他の人が十分な答えを提供しています。
ただし、警戒してください。砲撃は問題がないわけではありません。しかし、Perlまたはsedは、時間枠内で25GBのテキストをクロールして変更するために広く利用できる唯一のツールである可能性があります。