读重文本文件

时间:2013-06-03 11:07:48

标签: java android io

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

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

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

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

6 个答案:

答案 0 :(得分:1)

尝试使用InputStream代替BufferedReader

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

答案 1 :(得分:1)

我猜你正在读一个本地文件。在这种情况下,最好将整个文件读入字节数组,然后转换为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文件,你可能没有正确构建你的应用程序。

答案 2 :(得分:1)

bufferSize使用的默认BufferedRedaer8KB,但由于您逐行阅读累积会更多。要改善这一点,您可以使用:

BufferedReader(Reader in, int sz)< - 使用价值较小的sz4KB

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

close()< - 读者实例掌握的任何内存现在都可以GCed

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

答案 3 :(得分:0)

你正在解析JSON。

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

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

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

答案 4 :(得分:0)

您的代码......正如所写的......读取行并将其累积在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“对象”转换为代表整个事物的内存树结构。

答案 5 :(得分:0)

发送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.
}