【问题标题】:How StringBuilder can be used to read large text files in Java?如何使用 StringBuilder 读取 Java 中的大型文本文件?
【发布时间】:2012-03-24 17:28:08
【问题描述】:

Java 中是否有任何机制可以减少读取大型文本文件时的内存使用量?

我遇到的几乎每个程序都使用 String 来读取文本文件。但是 Java 为每个 String 文字保留空间。这就是为什么我认为内存使用量会增加,因为所有 String 对象都被存储了。 java.io 的所有类都处理字符串。但是如果我们不使用 StringBuilder 那么我们如何减少内存使用呢?

毕竟减少内存使用是 StringBuilder 的主要关注点[因为它不像 String 那样不可变]。那么我们如何在不使用 String 的情况下在 Java I/O 操作中利用它的特性,即不使用类似这样的东西:sb.append([String object]);

【问题讨论】:

  • 通常处理大文件背后的秘密不是试图将它们完全读入内存,而且你不需要 StringBuilder。
  • 有什么顾虑。您是否尝试将整个文件读入字符串?
  • 字符串字面量与文件 i/o 没有任何关系
  • 这与使用字符串常量池不同。如果您不想使用字符串,请使用字节缓冲区。你是否真的对任何东西进行了分析,甚至看看你是否关心你将做出的相对较小的性能/内存改进?
  • 当您从文件中读取时,您并没有创建字符串文字,因为没有文字——我不确定您为什么看不到它。为了有一个字符串文字,必须有一个文字 - 在你的例子中,有 - 它是"abc"。当您从文件中读取时,您并没有这样做。

标签: java string io stringbuilder stringbuffer


【解决方案1】:

假设您有 n 字符串,您从输入中读取每个长度为 1 的字符串 - 为简单起见。

在读取时对字符串使用operator+ 将在每次连接字符串时创建一个String 对象,因此您会得到长度为1,2,3,...,n 的字符串

因此,除了您从输入中读取的 n 字符串之外,组合字符串的总内存使用量为 1 + 2 + .. + n = O(n^2)

如果您使用StringBuilder 创建最终字符串,您实际上会创建n - 用于输入[每个长度为1] 并为最终字符串创建一个对象- 大小为n,因此总内存使用量为1 + 1 + .. + 1 + n = O(n)

因此,即使您使用 sb.append(String) - 空间使用率也比创建所有中间字符串要好 - 因为您不需要创建中间字符串对象。

此外 - 使用 StringBuilder 时性能 [时间] 应该更好 - 既因为您创建的对象更少,也因为更少的内存使用 - gc 不需要像天真地连接字符串时那样努力工作.

(*)请注意,很容易看出上面仍然适用于任何长度的字符串。

【讨论】:

    【解决方案2】:

    你可以使用 StringBuilders 的 append char 方法,避免创建中间字符串,看这个帖子:https://stackoverflow.com/a/9849624/102483 请记住,没有办法减少最终 String 的内存占用,使其小于您正在阅读的文件的大小。

    【讨论】:

      【解决方案3】:

      根据您的操作,您可以创建一个 String 和/或 StringBuilder 对象池,这些对象加载了您需要的值、清除然后重用。您可以将池配置为增长到最大值,如果池中的对象未使用,则将它们设置为 null,最终它们将被垃圾收集器回收。

      【讨论】:

        【解决方案4】:

        您可能需要考虑这样的事情:

          BufferedReader reader = 
            new BufferedReader(
              new InputStreamReader(
                new ByteArrayInputStream(data)));
          String line;
        
          while ((line = reader.readLine()) != null)
            ...
        

        查看这些链接了解更多详情:

        BufferedReader for large ByteBuffer?

        http://www.tutorialspoint.com/java/java_bytearrayinputstream.htm

        【讨论】:

        • 将其放入 StringBuilder 会导致 Android 上出现 OutOfMemory 错误,因为字符串仅占总内存大小的 2.5%。
        【解决方案5】:

        Reader 及其子类基于 char 和 char[],只有便捷方法使用 String。由于 StringBuilder.append() 接受 char[],如果只使用围绕 char[] 构建的方法,则可以避免创建不必要的 String 对象。

        请注意,虽然这会减少临时创建的 String 对象的数量,但总体内存需求保持不变,但 gc 会收集任何其他创建的 String。

        【讨论】:

          【解决方案6】:

          尝试使用StringBuilder 代替 String 来附加从 一份文件。如果您使用String,您最终可能会创建多个 内存中的字符串对象。

          【讨论】:

            猜你喜欢
            • 2011-08-17
            • 2012-12-11
            • 2013-09-01
            • 1970-01-01
            • 2011-01-10
            • 2020-03-10
            • 2015-02-20
            • 1970-01-01
            • 2014-06-18
            相关资源
            最近更新 更多