Javaとメモリの問題をよく知っている人からのアドバイスが必要です。大きなファイル(1.5GBのようなもの)があり、このファイルを多く(100の小さなファイル例)小さいファイル。
私は一般的にそれを行う方法を知っています(BufferedReader
を使用)が、メモリに関するアドバイス、またはそれをより速く行うためのヒントがあれば教えてください。
ファイルにテキストが含まれていますが、バイナリではなく、1行に約20文字あります。
まず、ファイルにバイナリデータが含まれている場合、BufferedReader
を使用すると大きな間違いになります(データを文字列に変換するため、これは不要であり、データを簡単に破損する可能性があるため)。代わりにBufferedInputStream
を使用する必要があります。テキストデータであり、改行に沿って分割する必要がある場合は、BufferedReader
を使用しても問題ありません(ファイルに適切な長さの行が含まれていると仮定します)。
メモリに関しては、適切なサイズのバッファを使用しても問題はありません(少なくとも1MBを使用して、HDがほぼ順次読み取りと書き込みを行うようにします)。
速度が問題であることが判明した場合は、Java.nio
パッケージ-それらはおそらくJava.io
、
メモリを節約するために、メモリにデータを不必要に保存/複製しないでください(つまり、ループ外の変数にデータを割り当てないでください)。入力が入ったらすぐに出力を処理するだけですimmediately.
BufferedReader
を使用しているかどうかは関係ありません。暗示的に示唆されているように、大幅に多くのメモリを消費することはありません。せいぜいパフォーマンスから数%しかヒットしません。 NIOの使用にも同じことが当てはまります。メモリの使用ではなく、スケーラビリティのみが向上します。同じファイルで何百ものスレッドを実行している場合にのみ興味深いものになります。
ファイルをループし、読み込んだらすぐにすべての行を他のファイルに書き込み、行をカウントし、100に達したら、次のファイルに切り替えます。
キックオフの例:
String encoding = "UTF-8";
int maxlines = 100;
BufferedReader reader = null;
BufferedWriter writer = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream("/bigfile.txt"), encoding));
int count = 0;
for (String line; (line = reader.readLine()) != null;) {
if (count++ % maxlines == 0) {
close(writer);
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("/smallfile" + (count / maxlines) + ".txt"), encoding));
}
writer.write(line);
writer.newLine();
}
} finally {
close(writer);
close(reader);
}
FileChannel sを使用して、メモリマップファイルの使用を検討できます。
通常、大きなファイルの場合はalotより高速です。 couldによりパフォーマンスが低下するため、パフォーマンスが低下するため、YMMVを使用します。
Javaで行う必要がありますか?つまりプラットフォームに依存しない必要がありますか?そうでない場合は、* nixで「 split 」コマンドを使用することをお勧めします。本当に必要な場合は、Javaプログラムを介してこのコマンドを実行できます。私はテストしていませんが、どのようなJava IO実装よりも速く実行できると思います。
これは非常に良い記事です。 http://Java.Sun.com/developer/technicalArticles/Programming/PerfTuning/
要約すると、優れたパフォーマンスを得るには、次のことを行う必要があります。
たとえば、ディスクへのアクセスを減らすために、大きなバッファを使用できます。この記事では、さまざまなアプローチについて説明します。
package all.is.well;
import Java.io.IOException;
import Java.io.RandomAccessFile;
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import junit.framework.TestCase;
/**
* @author Naresh Bhabat
*
Following implementation helps to deal with extra large files in Java.
This program is tested for dealing with 2GB input file.
There are some points where extra logic can be added in future.
Pleasenote: if we want to deal with binary input file, then instead of reading line,we need to read bytes from read file object.
It uses random access file,which is almost like streaming API.
* ****************************************
Notes regarding executor framework and its readings.
Please note :ExecutorService executor = Executors.newFixedThreadPool(10);
* for 10 threads:Total time required for reading and writing the text in
* :seconds 349.317
*
* For 100:Total time required for reading the text and writing : seconds 464.042
*
* For 1000 : Total time required for reading and writing text :466.538
* For 10000 Total time required for reading and writing in seconds 479.701
*
*
*/
public class DealWithHugeRecordsinFile extends TestCase {
static final String FILEPATH = "C:\\springbatch\\bigfile1.txt.txt";
static final String FILEPATH_WRITE = "C:\\springbatch\\writinghere.txt";
static volatile RandomAccessFile fileToWrite;
static volatile RandomAccessFile file;
static volatile String fileContentsIter;
static volatile int position = 0;
public static void main(String[] args) throws IOException, InterruptedException {
long currentTimeMillis = System.currentTimeMillis();
try {
fileToWrite = new RandomAccessFile(FILEPATH_WRITE, "rw");//for random write,independent of thread obstacles
file = new RandomAccessFile(FILEPATH, "r");//for random read,independent of thread obstacles
seriouslyReadProcessAndWriteAsynch();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName());
long currentTimeMillis2 = System.currentTimeMillis();
double time_seconds = (currentTimeMillis2 - currentTimeMillis) / 1000.0;
System.out.println("Total time required for reading the text in seconds " + time_seconds);
}
/**
* @throws IOException
* Something asynchronously serious
*/
public static void seriouslyReadProcessAndWriteAsynch() throws IOException {
ExecutorService executor = Executors.newFixedThreadPool(10);//pls see for explanation in comments section of the class
while (true) {
String readLine = file.readLine();
if (readLine == null) {
break;
}
Runnable genuineWorker = new Runnable() {
@Override
public void run() {
// do hard processing here in this thread,i have consumed
// some time and ignore some exception in write method.
writeToFile(FILEPATH_WRITE, readLine);
// System.out.println(" :" +
// Thread.currentThread().getName());
}
};
executor.execute(genuineWorker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
file.close();
fileToWrite.close();
}
/**
* @param filePath
* @param data
* @param position
*/
private static void writeToFile(String filePath, String data) {
try {
// fileToWrite.seek(position);
data = "\n" + data;
if (!data.contains("Randomization")) {
return;
}
System.out.println("Let us do something time consuming to make this thread busy"+(position++) + " :" + data);
System.out.println("Lets consume through this loop");
int i=1000;
while(i>0){
i--;
}
fileToWrite.write(data.getBytes());
throw new Exception();
} catch (Exception exception) {
System.out.println("exception was thrown but still we are able to proceeed further"
+ " \n This can be used for marking failure of the records");
//exception.printStackTrace();
}
}
}
従来の入出力ストリームよりも高速なJava.nioを使用できます。
http://Java.Sun.com/javase/6/docs/technotes/guides/io/index.html
はい。また、read(Char []、int init、int end)のような引数でread()を使用することは、そのような大きなファイルを読み取るためのより良い方法だと思います(例:read(buffer、0、buffer.length))
また、バイナリデータ入力ストリームにBufferedInputStreamReaderの代わりにBufferedReaderを使用すると、値が欠落するという問題も発生しました。したがって、このような場合には、BufferedInputStreamReaderを使用する方がはるかに優れています。
行ごとに読み込むのではなく、誤って入力ファイル全体を読み込まない限り、主な制限はディスク速度です。 100行を含むファイルから始めて、1行ずつ100の異なるファイルに書き込み、現在のファイルに書き込まれた行数でトリガーメカニズムを動作させたい場合があります。そのプログラムは、状況に合わせて簡単に拡張できます。
引数なしでreadを使用しないでください。とても遅いです。バッファに読み込み、ファイルにすばやく移動することをお勧めします。
バイナリ読み取りをサポートしているため、bufferedInputStreamを使用します。
そしてそれだけです。