この回答に続き - >
私は必要Merge
私は一つの大きなファイルに自分の限界を、それらをソートしたい、すでにディスク上のファイルをソートNの機能をない以上、メモリされK lines in the memory (K < N)
たJavaが好ましく、私はソートその後、それらすべてを取得し、することはできませんので、
これまでのところ、私は以下のコードのようにしようとしましたが、私は(メモリにはない多くのK LINESより)行ごとにファイルのすべてのNを反復処理するための良い方法が必要です+ディスクに保存並べ替え、最終的なファイル
public void run() {
try {
System.out.println(file1 + " Started Merging " + file2 );
FileReader fileReader1 = new FileReader(file1);
FileReader fileReader2 = new FileReader(file2);
//......TODO with N ?? ......
FileWriter writer = new FileWriter(file3);
BufferedReader bufferedReader1 = new BufferedReader(fileReader1);
BufferedReader bufferedReader2 = new BufferedReader(fileReader2);
String line1 = bufferedReader1.readLine();
String line2 = bufferedReader2.readLine();
//Merge 2 files based on which string is greater.
while (line1 != null || line2 != null) {
if (line1 == null || (line2 != null && line1.compareTo(line2) > 0)) {
writer.write(line2 + "\r\n");
line2 = bufferedReader2.readLine();
} else {
writer.write(line1 + "\r\n");
line1 = bufferedReader1.readLine();
}
}
System.out.println(file1 + " Done Merging " + file2 );
new File(file1).delete();
new File(file2).delete();
writer.close();
} catch (Exception e) {
System.out.println(e);
}
}
よろしく、
あなたはこのようなものを使用することができます
public static void mergeFiles(String target, String... input) throws IOException {
String lineBreak = System.getProperty("line.separator");
PriorityQueue<Map.Entry<String,BufferedReader>> lines
= new PriorityQueue<>(Map.Entry.comparingByKey());
try(FileWriter fw = new FileWriter(target)) {
String header = null;
for(String file: input) {
BufferedReader br = new BufferedReader(new FileReader(file));
String line = br.readLine();
if(line == null) br.close();
else {
if(header == null) fw.append(header = line).write(lineBreak);
line = br.readLine();
if(line != null) lines.add(new AbstractMap.SimpleImmutableEntry<>(line, br));
else br.close();
}
}
for(;;) {
Map.Entry<String, BufferedReader> next = lines.poll();
if(next == null) break;
fw.append(next.getKey()).write(lineBreak);
final BufferedReader br = next.getValue();
String line = br.readLine();
if(line != null) lines.add(new AbstractMap.SimpleImmutableEntry<>(line, br));
else br.close();
}
}
catch(Throwable t) {
for(Map.Entry<String,BufferedReader> br: lines) try {
br.getValue().close();
} catch(Throwable next) {
if(t != next) t.addSuppressed(next);
}
}
}
このコードは、あなたの質問内のコードとは異なり、ヘッダ行を扱うことに注意してください。元のコードのように、それは入力行を削除します。それが意図されていない場合は、削除することができますDELETE_ON_CLOSE
オプションをしてまで、全読者の構成を簡略化
BufferedReader br = new BufferedReader(new FileReader(file));
あなたがファイルを持っているように、それは、メモリ内の正確限りのラインを持っています。
原則的に、メモリ内のより少ない行の文字列を保持することは可能ですが、必要なときに、それは疑わしい少し節約のためのパフォーマンスの災害となり、それらを再読み込み。例えばあなたがすでに持っているN
ため、あなたが持っているという事実のために、このメソッドを呼び出すときに、メモリ内の文字列をN
ファイル名を。
あなたはすべてのコストで、同時に開催された行の数を減らしたいときしかし、あなたは単にあなたの質問に示す方法を使用することができます。最終的な結果に最後の入力ファイルと一時ファイルをマージするまでは、その上の別の一時ファイルに第三と一時ファイルという一時ファイル、マージに最初の2つのファイルをマージし、そして。次に、あなたが持っているメモリのほとんどの2つのラインの文字列(のK == 2
オペレーティングシステムは、このアプローチの恐ろしいパフォーマンスを軽減しようとすると、バッファリングのために使用するよりも少ないメモリを節約します)、。
同様に、あなたがマージに上に示した方法で使用することができますK
一時ファイルにファイルを、[次へと一時ファイルマージK-1
残りと一時ファイルのマージされるまで、その上のファイルを、そしてK-1
最終的な結果に以下のファイルを、持っていますとメモリ消費量のスケーリングK < N
。このアプローチは、チューニングすることを可能K
に合理的な比率を有するようにN
速度用メモリを交換します。私が思うに、最も実用的な例では、K == N
うまく動作します。