在java中对巨大的file.txt进行排序

时间:2012-01-12 09:38:09

标签: java sorting text-files lines

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

我已经注意到有一个起始文件的讨论与我的相似: Sorting Lines Based on words in them as keys

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

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

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

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

6 个答案:

答案 0 :(得分:15)

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

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

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

  3. 删除所有临时文件。

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

答案 1 :(得分:2)

您可以使用

运行以下命令
-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

答案 2 :(得分:1)

算法:

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

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

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

  3. 完成后,请逐一合并。

  4. 上述算法也称为外部排序。第3步称为 N-way merge

答案 3 :(得分:0)

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

答案 4 :(得分:0)

divide and conquer是最佳解决方案:)

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

链接:

Sort a file with huge volume of data given memory constraint

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

答案 5 :(得分:-2)

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

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