Java 合并排序文件

Java 合并排序文件,java,Java,im使用Java实现外部合并排序 因此,给定一个文件,我将其拆分为较小的文件,然后对较小的部分进行排序,最后合并排序后的(较小的)文件 所以,最后一步就是我遇到的问题 我有一个文件列表,我希望在每个步骤中,取每个文件前几行的最小值,然后删除该行 所以,应该是这样的: public static void mergeSortedFiles(List<File> sorted, File output) throws IOException { BufferedWriter wf

im使用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);
}
publicstaticvoidmergesortedfile(列表排序,文件输出)引发IOException{
BufferedWriter wf=新的BufferedWriter(新文件写入程序(输出));
字符串卷曲=”;
而(!sorted.isEmpty()){
curLine=findMinLine(已排序);
书写(卷曲线);
}
}
公共静态字符串findMinLine(列表排序)引发IOException{
List brs=new ArrayList();

对于(int i=0;i那么您要做的是交换一个文本文件中的两行?您可以使用
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();
List lines1=Files.readAllLines(youFile1);
List lines2=Files.readAllLines(youFile2);
//在这些行上使用合并排序
合并列表;
FileWriter writer=新的FileWriter(yourOutputFile);
for(字符串str:merged){
writer.write(str+System.lineSeparator());
}
writer.close();

那么您要做的是在一个文本文件中交换两行吗?您可以使用
随机访问文件来进行交换,但是这会非常慢,因为每次交换两行时都必须等待下一个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();
List lines1=Files.readAllLines(youFile1);
List lines2=Files.readAllLines(youFile2);
//在这些行上使用合并排序
合并列表;
FileWriter writer=新的FileWriter(yourOutputFile);
for(字符串str:merged){
writer.write(str+System.lineSeparator());
}
writer.close();

您可以围绕每个文件创建一个
可比较的
包装器,然后将包装器放在堆中(例如
优先级队列


您可以围绕每个文件创建一个
可比较的
包装器,然后将包装器放在堆中(例如
优先级队列


固定数量的文件(例如2个)之间的标准合并技术是:

  • 为每个文件的当前记录的排序键的值设置一个变量(对于java,使该变量具有可比性)
  • 通过读取每个文件的第一条记录(并填写相应的变量)开始该过程
  • 通过一个代码块循环(直到两者上的文件结束),该代码块表示
如果(key_1.compareTo(key_2)==0){处理两个文件;然后读取两个文件} 否则,如果(key_1.compareTo)(key_2)=-1){处理文件1;然后读取文件1} else{处理文件2;然后读取文件2}

请注意,这段代码基本上只不过是确定具有最低密钥的文件,并对其进行处理


如果文件数是可变的,则键变量数也是可变的,“确定具有最低当前键的文件”无法按上述方式执行。相反,请使用与文件数量相同的当前\u key\u value对象,并将它们全部存储在树集中。现在,树集的第一个元素将是所有文件中当前键值最低的元素,如果确保在键变量和文件号之间保持链接,则只需处理该文件(并从树集中删除刚刚处理的键值,从处理过的文件中读取一条新记录,并将其键值添加到树集中)。

固定数量的文件(例如,2)之间的标准合并技术是:

  • 为每个文件的当前记录的排序键的值设置一个变量(对于java,使该变量具有可比性)
  • 通过读取每个文件的第一条记录(并填写相应的变量)开始该过程
  • 通过一个代码块循环(直到两者上的文件结束),该代码块表示
如果(key_1.compareTo(key_2)==0){处理两个文件;然后读取两个文件} 否则,如果(key_1.compareTo)(key_2)=-1){处理文件1;然后读取文件1} else{处理文件2;然后读取文件2}

请注意,这段代码基本上只不过是确定具有最低密钥的文件,并对其进行处理


如果文件数是可变的,则键变量数也是可变的,“确定具有最低当前键的文件”无法按上述方式执行。相反,请使用与文件数量相同的当前\u key\u value对象,并将它们全部存储在树集中。现在,树集的第一个元素将是所有文件中当前键值最低的元素,如果确保在键变量和文件号之间保持链接,则只需处理该文件(并从树集中删除刚刚处理过的键值,从处理过的文件中读取一条新记录并将其键值添加到树集中)。

为什么第一个参数是
文件
对象列表?使用两个输入参数不是更容易吗?类似于
合并排序文件(文件左、文件右、文件输出)
因为您只在两个文件上使用了“合并”。这将在始终只有两个输入文件的情况下删除大量列表处理。@Progman我需要合并所有已排序的文件,您的意思是我应该一次将它们合并为两个文件吗?这是“合并排序”中通常执行的操作。您只合并了两个输入,而不是N个输入。@Progman我不确定使用文件的内存限制合并是否正确。例如,我想知道Spark如何收集排序的RDD。当然,通过成对合并所有文件,您可以并行做更多事情,但实现起来要复杂得多。为什么
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