【问题标题】:sorting lines of an enormous file.txt in java在java中对巨大file.txt的行进行排序
【发布时间】:2012-02-08 14:36:40
【问题描述】:

我正在处理一个非常大的文本文件 (755Mb)。 我需要对这些行(大约 1890000)进行排序,然后将它们写回到另一个文件中。

我已经注意到开始文件与我的非常相似的讨论: Sorting Lines Based on words in them as keys

问题是我无法将行存储在内存中的集合中,因为我得到了 Java 堆空间异常(即使我将其扩展为最大)..(已经尝试过!)

我不能用excel打开它并使用排序功能,因为文件太大,无法完全加载..

我考虑过使用数据库..但我认为编写所有行然后使用 SELECT 查询执行时间太长了..我错了吗?

任何提示表示赞赏 提前致谢

【问题讨论】:

  • 嗯,“太长”取决于您的期望。如果你希望在半秒内完成,那确实太长了。如果您不介意等待几秒钟或几分钟,那应该不是问题。试一试,看看时间是否合理。
  • 您应该能够使用最新版本的 Java 将文件存储在大约 1 GB 堆的内存中。即-XX:+UseCompressedStrings

标签: java sorting text-files lines


【解决方案1】:

为什么不尝试多线程并增加正在运行的程序的堆大小? (这也需要您使用合并排序之类的东西,前提是您的系统中有超过 755mb 的内存。)

【讨论】:

  • 见上面 Eric.Sun 的评论。
  • 是的,你的理由在非常非常大的文件中显然很有用。但是 OP 指定文件大小为 755mb,而今天的大多数计算机都超过 755mb。如果我们可以用 -Xmx1024m 解决他/她的问题,为什么还要使用复杂的算法?
  • 归并排序不是一个过于复杂的算法。我不想对算法使用的硬件做出假设。此外,该进程可能不是设备上运行的唯一软件。以我的拙见,编写 50 行代码来节省超过 GB 的内存(如果是字符串,每行可能占用几个字节)非常值得付出努力。 (无意冒犯。)
  • 不,无论如何我都同意你的看法。如果我处于类似的情况,我会先尝试增加堆大小。如果这不起作用,我可能会按照您的建议进行操作。一切都很好:)
  • 很公平。让我们在这两种解决方案上妥协,即尝试内存方法并记录一张票,以便在稍后阶段 (+1) 用内存效率更高的方法(附带测试用例)替换它。
【解决方案2】:

我认为这里的解决方案是使用临时文件进行合并排序:

  1. 读取第一个文件的前 n 行,(n 是您可以在内存中存储和排序的行数),对它们进行排序, 并将它们写入文件1.tmp(或者你怎么称呼它)。对接下来的 n 行执行相同操作并将其存储在 2.tmp 中。重复直到处理完原始文件的所有行。

  2. 读取每个临时文件的第一行。确定最小的一个(根据您的排序顺序),将其写入目标文件,并从相应的临时文件中读取下一行。重复直到处理完所有行。

  3. 删除所有临时文件。

这适用于任意大文件,只要您有足够的磁盘空间。

【讨论】:

  • 我完全同意。可以使用“合并排序”算法来完成
【解决方案3】:

divide and conquer 是最好的解决方案:)

将您的文件分成较小的文件,分别对每个文件进行排序,然后重新组合。

链接:

Sort a file with huge volume of data given memory constraint

http://hackerne.ws/item?id=1603381

【讨论】:

    【解决方案4】:

    算法:

    我们有多少可用内存?假设我们有X MB 的可用内存。

    1. 将文件分成K 块,其中X * K = 2 GB。将每个块放入内存并像往常一样使用任何O(n log n) 算法对行进行排序。将这些行保存回文件。

    2. 现在将下一个块放入内存并排序。

    3. 完成后,将它们一一合并。

    上述算法也称为外部排序。第 3 步称为 N 路合并

    【讨论】:

      【解决方案5】:

      也许你可以使用 perl 来格式化文件。然后像 mysql 一样加载到数据库中。它是如此之快。并使用索引查询数据。并写入另一个文件。

      你可以设置jvm堆大小,比如'-Xms256m -Xmx1024m'。我希望能帮助你。谢谢

      【讨论】:

      • 使用基于文件的合并排序比简单地分配更多内存要好得多。如果文件变得更大,即 10gigs,会发生什么?
      【解决方案6】:

      您可以运行以下命令

      -mx1g -XX:+UseCompressedStrings  # on Java 6 update 29
      -mx1800m -XX:-UseCompressedStrings  # on Java 6 update 29
      -mx2g  # on Java 7 update 2.
      

      import java.io.*;
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.List;
      
      public class Main {
          public static void main(String... args) throws IOException {
              long start = System.nanoTime();
              generateFile("lines.txt", 755 * 1024 * 1024, 189000);
      
              List<String> lines = loadLines("lines.txt");
      
              System.out.println("Sorting file");
              Collections.sort(lines);
              System.out.println("... Sorted file");
              // save lines.
              long time = System.nanoTime() - start;
              System.out.printf("Took %.3f second to read, sort and write to a file%n", time / 1e9);
          }
      
          private static void generateFile(String fileName, int size, int lines) throws FileNotFoundException {
              System.out.println("Creating file to load");
              int lineSize = size / lines;
              StringBuilder sb = new StringBuilder();
              while (sb.length() < lineSize) sb.append('-');
              String padding = sb.toString();
      
              PrintWriter pw = new PrintWriter(fileName);
              for (int i = 0; i < lines; i++) {
                  String text = (i + padding).substring(0, lineSize);
                  pw.println(text);
              }
              pw.close();
              System.out.println("... Created file to load");
          }
      
          private static List<String> loadLines(String fileName) throws IOException {
              System.out.println("Reading file");
              BufferedReader br = new BufferedReader(new FileReader(fileName));
              List<String> ret = new ArrayList<String>();
              String line;
              while ((line = br.readLine()) != null)
                  ret.add(line);
              System.out.println("... Read file.");
              return ret;
          }
      }
      

      打印

      Creating file to load
      ... Created file to load
      Reading file
      ... Read file.
      Sorting file
      ... Sorted file
      Took 4.886 second to read, sort and write to a file
      

      【讨论】:

      • 能否用jdk7u2重复测试,看看需要多少内存和时间?
      • 不幸的是 Java 7 不支持这个选项stackoverflow.com/questions/8833385/…
      • 是的,但仍然想看看它在没有该选项的情况下使用了多少内存。也许他们已经进行了改进,因此不再需要此选项。
      • @dogbane 一个合理的问题,在关闭压缩字符串的情况下,Java 7 比 Java 6 需要多 200 MB。 :]
      猜你喜欢
      • 2021-02-15
      • 1970-01-01
      • 2011-11-28
      • 2015-02-21
      • 2017-02-09
      • 1970-01-01
      • 1970-01-01
      • 2015-10-10
      • 2019-09-06
      相关资源
      最近更新 更多