我只需要N個已經(jīng)排序的磁盤上的文件的Merge功能,
我想將它們分成一個大文件我的限制是內(nèi)存不超過內(nèi)存中的K行(K<n)所以我無法獲取所有它們?nèi)缓笈判?首選java
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èi)存行.
原則上,可以在內(nèi)存中保留較少的線串,在需要時重新讀取它們,這對于可疑的少量保存來說將是性能災難.例如.由于您有N個文件名,因此在調(diào)用此方法時,您在內(nèi)存中已經(jīng)有N個字符串.
但是,當您想要不惜一切代價減少同時保留的行數(shù)時,您只需使用問題中顯示的方法即可.將前兩個文件合并到一個臨時文件中,將該臨時文件與第三個文件合并到另一個臨時文件,依此類推,直到將臨時文件與最后一個輸入文件合并到最終結果.然后你在內(nèi)存中最多有兩個線串(K == 2),比操作系統(tǒng)用于緩沖的內(nèi)存節(jié)省更少,試圖減輕這種方法的可怕性能.
同樣,您可以使用上面顯示的方法將K文件合并到一個臨時文件中,然后將臨時文件與下一個K-1文件合并,依此類推,直到將臨時文件與剩余的K-1或更少文件合并為止最終結果是,在K <1的情況下進行存儲器消耗縮放. N.這種方法允許調(diào)整K以使其具有合理的N比率,以便將速度換成記憶.我認為,在大多數(shù)實際情況中,K == N將會正常工作.