[英]merging sorted files Java
即時通訊使用Java實現外部合並排序。
因此,給定一個文件,我將其拆分為較小的文件,然后對較小的部分進行排序,最后合並已排序的(較小的)文件。
因此,最后一步是我遇到的麻煩。
我有一個文件列表,我想在每個步驟中,取每個文件的第一行的最小值,然后刪除該行。
因此,應該是這樣的:
public static void mergeSortedFiles(List<File> sorted, File output) throws IOException {
BufferedWriter wf = new BufferedWriter(new FileWriter(output));
String curLine = "";
while(!sorted.isEmpty()) {
curLine = findMinLine(sorted);
wf.write(curLine);
}
}
public static String findMinLine(List<File> sorted) throws IOException {
List<BufferedReader> brs = new ArrayList<>();
for(int i =0; i<sorted.size() ; i++) {
brs.add(new BufferedReader(new FileReader(sorted.get(i))));
}
List<String> lines = new ArrayList<>();
for(BufferedReader br : brs) {
lines.add(br.readLine());
}
Collections.sort(lines);
return lines.get(0);
}
我不確定如何更新文件,任何人都可以幫助您?
感謝您的幫助!
您可以圍繞每個文件創建一個Comparable
包裝器,然后將包裝器放置在堆中(例如PriorityQueue
)。
public class ComparableFile<T extends Comparable<T>> implements Comparable<ComparableFile<T>> {
private final Deserializer<T> deserializer;
private final Iterator<String> lines;
private T buffered;
public ComparableFile(File file, Deserializer<T> deserializer) {
this.deserializer = deserializer;
try {
this.lines = Files.newBufferedReader(file.toPath()).lines().iterator();
} catch (IOException e) {
// deal with it differently if you want, I'm just providing a working example
// and wanted to use the constructor in a lambda function
throw new UncheckedIOException(e);
}
}
@Override
public int compareTo(ComparableFile<T> that) {
T mine = peek();
T theirs = that.peek();
if (mine == null) return theirs == null ? 0 : -1;
if (theirs == null) return 1;
return mine.compareTo(theirs);
}
public T pop() {
T tmp = peek();
if (tmp != null) {
buffered = null;
return tmp;
}
throw new NoSuchElementException();
}
public boolean isEmpty() {
return peek() == null;
}
private T peek() {
if (buffered != null) return buffered;
if (!lines.hasNext()) return null;
return buffered = deserializer.deserialize(lines.next());
}
}
然后,您可以通過以下方式合並它們:
public class MergeFiles<T extends Comparable<T>> {
private final PriorityQueue<ComparableFile<T>> files;
public MergeFiles(List<File> files, Deserializer<T> deserializer) {
this.files = new PriorityQueue<>(files.stream()
.map(file -> new ComparableFile<>(file, deserializer))
.filter(comparableFile -> !comparableFile.isEmpty())
.collect(toList()));
}
public Iterator<T> getSortedElements() {
return new Iterator<T>() {
@Override
public boolean hasNext() {
return !files.isEmpty();
}
@Override
public T next() {
if (!hasNext()) throw new NoSuchElementException();
ComparableFile<T> head = files.poll();
T next = head.pop();
if (!head.isEmpty()) files.add(head);
return next;
}
};
}
}
這是一些代碼來演示它的工作原理:
public static void main(String[] args) throws IOException {
List<File> files = Arrays.asList(
newTempFile(Arrays.asList("hello", "world")),
newTempFile(Arrays.asList("english", "java", "programming")),
newTempFile(Arrays.asList("american", "scala", "stackoverflow"))
);
Iterator<String> sortedElements = new MergeFiles<>(files, line -> line).getSortedElements();
while (sortedElements.hasNext()) {
System.out.println(sortedElements.next());
}
}
private static File newTempFile(List<String> words) throws IOException {
File tempFile = File.createTempFile("sorted-", ".txt");
Files.write(tempFile.toPath(), words);
tempFile.deleteOnExit();
return tempFile;
}
輸出:
american
english
hello
java
programming
scala
stackoverflow
world
因此,您要在文本文件中交換兩行? 您可以通過使用RandomAccessFile
來完成此操作,但是這非常慢,因為每次交換兩行時都必須等待下一個IO突發。 因此,我強烈建議您使用以下代碼來對堆執行合並排序:
List<String> lines1 = Files.readAllLines(youFile1);
List<String> lines2 = Files.readAllLines(youFile2);
//use merge sort on theese lines
List<String> merged;
FileWriter writer = new FileWriter(yourOutputFile);
for(String str: merged) {
writer.write(str + System.lineSeparator());
}
writer.close();
固定數量的文件(例如2)之間的標准合並技術是:
如果(key_1.compareTo(key_2)== 0){處理兩個文件; 然后讀取兩個文件},否則(key_1.compareTo(key_2)== -1){處理文件1; 然后讀取文件1}否則{處理文件2; 然后讀取文件2}
請注意,這段代碼本質上僅是確定具有最低鍵的文件並進行處理而已。
如果文件數是可變的,那么鍵變量的數也是可變的,因此無法按照上述方法“確定當前鍵值最低的文件”。 取而代之的是,具有與文件一樣多的current_key_value對象,並將它們全部存儲在TreeSet中。 現在,TreeSet的第一個元素將是所有文件中最低的當前鍵值,如果您確保在鍵變量和文件編號之間保持鏈接,則只需處理該文件(並刪除剛剛處理的鍵值)從TreeSet中讀取並從處理的文件中讀取一條新記錄,並將其鍵值添加到TreeSet中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.