繁体   English   中英

读重文本文件

[英]Read heavy text file

我必须阅读一个大文本文件(大约5兆字节)。

为了读取这个文件,我使用BufferedReader()但它导致内存泄漏和堆增长,是否有任何替代选项来优化我的代码?

            StringBuffer sb = new StringBuffer();
            BufferedReader reader = new BufferedReader(new FileReader(vCache));
            String line = null;

            while ((line = reader.readLine()) != null) 
            {
                sb.append(line);
            }

尝试使用InputStream而不是BufferedReader

try {
    InputStream is = new FileInputStream(vCache);
    byte[] b = new byte[is.available()];
    is.read(b);
    String text = new String(b);
}

我猜你正在读一个本地文件。 在这种情况下,您可能最好将整个文件读入字节数组,然后转换为String:

InputStream is = new FileInputStream(vCache);
byte[] buffer = new byte[is.available()];
is.read(buffer);
is.close();
jsonContent = new String(buffer, "UTF-8");

但是,您可能仍然通过将Android中的这么大的文件读入内存来引发问题。 我想说如果你需要读取一个5 MB的json文件,你可能没有正确构建你的应用程序。

BufferedRedaer使用的默认bufferSize8KB ,但是因为你逐行读取累积会更多。 要改善这一点,您可以使用:

BufferedReader(Reader in, int sz) < - 使用较小值的sz表示4KB

read(char[] cbuf) < - 约束cbuf大小与读者大小相同

close() < - 读者实例掌握的内存现在可以被GC

现在你的代码StringBuffer sb保存完整文件内容中的所有行,即使在进行了上述更改后,如果JVM无法使用所需的内存(~fileSize),您将再次出现在OOM问题中。 我不确定你是否就是这种情况,否则上面应该会改善局部内存峰值。

你正在解析JSON。

您可以通过删除美化(例如缩进,换行等)来使输入文件更小。

您还可以尝试直接从流中读取的解析器,希望它不需要一次缓冲所有内容。 例如,Android提供了JsonReader ,它允许您自己解析流并控制数据结构,这意味着您可以使用更多内存有效的结构,并且它也不会缓冲整个流。 不幸的是,它是在API级别11中添加的,因此向后兼容性可能是个问题。

一种替代方案是,如果顶级对象是一个数组,则将其拆分为几个较小的数组,可能在不同的文件中,分别解析它们并合并子数组。 如果基础对象具有相似的结构,则可以在合并之前将它们转换为Java对象,这将具有更紧凑的内存结构。

你的代码......写成...读取行并在StringBuilder累积它们。 你正在积累线条这一事实只是一种内存泄漏。

防止泄漏的最佳方法是将应用程序更改为以下方式:

    BufferedReader reader = new BufferedReader(new FileReader(vCache));
    String line = null;
    while ((line = reader.readLine()) != null) {
        process(line);
    }

换句话说,不要在内存中累积行。 在阅读它们时处理它们然后丢弃它们。


如果您的处理是必须在内存中累积行,那么如果您像这样分配StringBuilder ,您将获得更好的内存使用:

    StringBuilder sb = new StringBuilder(fileSizeInCharacters);

这将避免重新分配的需要,这可能(在最坏的情况下)需要3倍于文件大小(以字符为单位)的字符。

但是,迟早会遇到同样的问题。 累积内存中的文件内容无法扩展。


您的评论表明这确实是一个JSON处理问题。 这是关于流式JSON处理主题的问答:

流API的想法是您不需要将JSON“对象”转换为代表整个事物的内存树结构。

发送JSON,使每行对应一个完整的db行和格式良好的json。 这样您就不必一起处理整个文件。

//StringBuffer sb = new StringBuffer();
BufferedReader reader = new BufferedReader(new FileReader(vCache));
String line = null;

while ((line = reader.readLine()) != null)  {
  //Parse JSON
  //Insert into local SQLite DB.
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM