分享

java – 如何排序N个文件

 印度阿三17 2019-08-27

我只需要N个已经排序的磁盘上的文件的Merge功能,

我想将它们分成一个大文件我的限制是内存不超过内存中的K行(K<n)所以我无法获取所有它们然后排序,首选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个文件名,因此在调用此方法时,您在内存中已经有N个字符串.

但是,当您想要不惜一切代价减少同时保留的行数时,您只需使用问题中显示的方法即可.将前两个文件合并到一个临时文件中,将该临时文件与第三个文件合并到另一个临时文件,依此类推,直到将临时文件与最后一个输入文件合并到最终结果.然后你在内存中最多有两个线串(K == 2),比操作系统用于缓冲的内存节省更少,试图减轻这种方法的可怕性能.

同样,您可以使用上面显示的方法将K文件合并到一个临时文件中,然后将临时文件与下一个K-1文件合并,依此类推,直到将临时文件与剩余的K-1或更少文件合并为止最终结果是,在K <1的情况下进行存储器消耗缩放. N.这种方法允许调整K以使其具有合理的N比率,以便将速度换成记忆.我认为,在大多数实际情况中,K == N将会正常工作.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多