【问题标题】:The best way to read a huge file (for example a very large text document)读取大文件的最佳方式(例如非常大的文本文档)
【发布时间】:2014-03-18 14:06:10
【问题描述】:

我是 java 新手...在我当前的项目中,我需要读写一个非常大的文本文件(1 GB - 5 GB)...首先我使用了这些类:BufferedReaderBufferedWriter

public static String read(String dir) {
    BufferedReader br;
    String result = "", line;
    try {
        br = new BufferedReader(new InputStreamReader(new FileInputStream(dir), "UTF-8"));
        while ((line = br.readLine()) != null) {
            result += line + "\n";
        }
    } catch (IOException ex) {
        //do something
    }
    return result;
}

public static void write(String dir, String text) {
    BufferedWriter bw;
    try {
        bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(dir), "UTF-8"));
        bw.write("");
        for (int i = 0; i < text.length(); i++) {
            if (text.charAt(i) != '\n') {
                bw.append(text.charAt(i));
            } else {
                bw.newLine();
            }
        }
        bw.flush();
    } catch (IOException ex) {
        //do something
    }
}

这个类工作得很好,但不适用于大文件...

然后我将 MappedByteBuffer 用于read() 方法(我不知道如何使用此类编写文件):

public static String read(String dir) {
    FileChannel fc;
    String s = "";
    try {
        fc = new RandomAccessFile(dir, "r").getChannel();
        MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
        buffer.load();
        buffer.force();
        for (int i = 0; i < buffer.limit(); i++) {
            s += (char) buffer.get();
        } //I know the problem is here
        buffer.clear();
        inChannel.close();
    } catch (IOException e) {
        //do something
    }
    return s;
}

但仍然无法读取大文件(超过 30-40 MB),即使记事本也比我的应用程序快 :))

还有一个问题是我不知道如何以第二种方式更改编码(例如“UTF-8”、“ANSI”、...)

各位,请告诉我哪种方式是读写 laaaarge 文件的最佳方式? 有什么想法吗?

【问题讨论】:

  • 你想对所有这些文本做什么?
  • 您根本不应该将 1-2GB 的文件读入 String - 这将是 a) 缓慢和 b) 内存密集型。您可能需要对文件进行一些转换,以便 stream 它 - 一次读取和写入一行。更重要的是,我会推荐 this article 在 Java 中使用字符串。
  • try (InputStream in = new BufferedInputStream(new FileInputStream(dir))) { while (in.read() != -1); } - 看起来你实际上并没有对你读过的数据做任何事情,所以这应该对你有用,而且速度非常快。
  • 在 TextArea 上显示它并进行一些搜索并将结果保存在日志文件中
  • 像记事本这样的程序会在您滚动时流式传输文件并执行各种其他优化。您不能只将 2GB 的数据转储到 TextArea。就搜索而言,如果文件那么大,您将需要以某种方式对其进行索引。

标签: java bufferedreader bytebuffer mappedbytebuffer


【解决方案1】:
result += line + "\n";

这一行试图将整个文件内容保存在内存中。尝试像这样在阅读时处理每一行

while ((line = br.readLine()) != null) {
            processLine( line ); // this may write it to another file.
        }

【讨论】:

    【解决方案2】:

    至少,我建议改变

    result += line + "\n";
    

    到 StringBuilder。

    resultBldr.append(line).append("\n");
    

    这避免了在每一行上创建一个新的字符串对象——一个越来越大越来越大的字符串对象!

    此外,您绝对应该将输出写入文件逐行。不要累积所有文本然后然后输出它。

    换句话说,在这种情况下,不建议将您的readwrite 函数完全分开。

    【讨论】:

    • 我不明白这是什么:aaa\naaa\naaa...
    • 你的意思是没有行分隔符?这只是一条大线?使用write(s + "\n");println(s); 或其他任何方式在每个末尾添加一个。
    • 我对此并不熟悉。试试这个:google.com/search?q=change+encoding+to+utf+java
    【解决方案3】:

    认为字符串的每个连接都会创建一个新字符串,因此,如果您读取 40 MB 大文件中的每个字符并连接起来,您总共会创建 40.000.000 个字符串,例如 read()

    尝试使用StringBuffer 而不是String,这对于这种情况是值得推荐的。

    【讨论】:

    • 如果您没有线程安全要求,则首选StringBuilder
    【解决方案4】:

    一次读取 1GB - 5GB 范围内的大文件总是一个坏主意。头顶会有巨大的性能,你的应用程序会变慢。

    最好将这个巨大的文件分割成更小的块并逐块读取。我认为如果您开始以较小的块读取文件,那么您编写的代码将可以正常工作。

    您是否听说过专门用于处理海量数据的 HDFS 系统、Solr 索引、apache hadoop 框架。你可能想看看它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多