簡體   English   中英

合並排序的文件Java

[英]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)之間的標准合並技術是:

  • 為每個文件的當前記錄的排序鍵的值提供一個變量(對於Java,使該變量為Comparable)。
  • 通過讀取每個文件的第一條記錄開始該過程(並填寫相應的變量)
  • 循環(直到兩個文件的末尾)通過本質上說的代碼塊

如果(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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM