web-dev-qa-db-ja.com

25GBの大きなテキストファイルの読み取りと処理

たとえば、25 GBの大きなテキストファイルを読み取る必要があり、このファイルを15〜20分以内に処理する必要があります。このファイルには、複数のヘッダーセクションとフッターセクションがあります。

CSplitでこのファイルをヘッダーに基づいて分割しようとしましたが、ヘッダーに基づいていくつかのファイルに分割するのに約24〜25分かかり、まったく受け入れられません。

BufferReaderBufferWiterFileReaderFileWriterと一緒に使用して、順次読み取りと書き込みを試みました。 27分以上かかります。繰り返しますが、それは受け入れられません。

各ヘッダーの開始インデックスを取得し、複数のスレッドを実行してRandomAccessFileを使用して特定の場所からファイルを読み取るなど、別のアプローチを試しました。しかし、これには運がありません。

どうすれば要件を達成できますか?

重複の可能性:

Javaで大きなファイルを読み取る

10
user1142292

データをより高速に処理するには、大きなバッファー読み取りサイズ(たとえば、2MBではなく20MB)を使用してみてください。また、速度と文字変換が遅いため、BufferedReaderを使用しないでください。

この質問は以前に尋ねられました: Javaで大きなファイルを読む

8
collinjsimpson

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を取得していることがわからない限り、ハードウェアに問題があります。

6
Peter Lawrey

Java.nioを使用して、オペレーティングシステムの機能をより有効に活用してみてください。データを(文字列などに)コピーすることは避けてください。ただし、offsetsを使用して作業してください。 Java.nioクラスには、データをJavaレイヤーにまったくプルせずに(少なくともLinuxでは)1つのバッファーから別のバッファーにデータを転送するメソッドさえあると思いますが、それは本質的に変換されますオペレーティングシステムコールに。

最近の多くのWebサーバーでは、この手法が静的データを提供できるパフォーマンスの鍵となっています。基本的に、メインメモリへの重複を避けるために、オペレーティングシステムに可能な限り委任します。

これを強調しておきます。25GBのバイトバッファをシークするだけで、Java文字列(文字セットのエンコード/デコードとコピーが必要になる場合があります)に変換するよりもはるかに高速です)。とメモリ管理が役立ちます。

1
Anony-Mousse

プラットフォームが適切な場合は、シェルアウトして、catとsedの組み合わせを呼び出すことをお勧めします。そうでない場合でも、コマンドラインからシェルアウトしてPerlを使用することをお勧めします。絶対にJava実際の処理を行う必要がある場合は、他の人が十分な答えを提供しています。

ただし、警戒してください。砲撃は問題がないわけではありません。しかし、Perlまたはsedは、時間枠内で25GBのテキストをクロールして変更するために広く利用できる唯一のツールである可能性があります。

1
0xCAFEBABE