在Java中读取大文件

时间:2012-04-24 17:35:10

标签: java string

我有一个适用于CSV文件的swing应用程序。它逐行读取完整文件,计算一些必需的统计信息并显示输出。 输出屏幕的上半部分以JTable中的顺序显示文件中的每条记录,而下半部分显示基于该数据计算的统计数据。问题是JVM占用的内存是文件大小的4倍。 (处理86MB文件堆区域时使用377 MB空间 - 使用jVisualVM检查内存利用率。)

注意:

  1. 我已经使用LineNumberReader来读取文件(因为有特殊要求,如果有助于内存使用,我可以更改它)

  2. 为了读取每一行,使用readLine(),然后为该记录的各个字段调用该行的字符串.split(',')。

  3. 存储在Vector中的每条记录都显示在JTable中,而其他统计信息存储在JavaBean类的HashMap,TreeMap和摘要数据中。还使用JFreeChart绘制了一个图表。

  4. 请建议降低内存利用率,因为我需要处理2GB文件。

4 个答案:

答案 0 :(得分:1)

尝试给OpenCSV一个镜头。它只在您使用readNext()方法时存储最后一行读取行。对于大文件,这是完美的。

在他们的网站上,以下是他们支持的功能:

  • 每行任意数量的值

  • 忽略引用元素中的逗号

  • 使用嵌入式回车符(即条目)处理带引号的条目 跨越多行)

  • 可配置的分隔符和引号字符(或使用合理的 缺省值)

  • 一次阅读所有条目,或使用Iterator样式模型

  • 从String []创建csv文件(即自动转义嵌入式文件) 引用字符)

答案 1 :(得分:0)

使用最佳做法升级程序

  1. 在程序中编写多线程以获得更好的CPU利用率。
  2. 设置堆最小和最大堆大小以更好地使用ram。
  3. 使用适当的数据结构和设计。

答案 2 :(得分:0)

每个Java对象都有a memory overhead,所以如果你的字符串很短,这可以解释为什么你的文件大小是你的4倍。您还必须计算Vector的大小及其内部结构。我认为Map不会提高内存使用率,因为Java Strings已尽可能尝试在内存中指向相同的地址。

我认为你应该修改你的设计。鉴于您的要求

  

输出屏幕的上半部分显示文件中的每条记录   在JTable中排序,而下半部分显示基于的计算统计   那个数据

您不需要将整个文件存储在内存中。您需要完全读取来计算统计信息,这当然可以使用非常少量的内存来完成。关于JTable部分,这可以通过多种方式实现,而需要2GB的堆空间用于您的程序!当有人想在内存中保留CSV时,我认为一定有问题! Apache IO LineIterator

答案 3 :(得分:0)

增加JVM堆大小(-Xms和-Xmx)。如果你有记忆,这是最好的解决方案。如果你不能这样做,你将需要找到一个折衷方案,它将是数据模型和表示(GUI)更改的组合,通常会导致代码复杂性增加和出现错误。

  1. 尝试修改统计算法,以便在读取数据时执行其工作,并且不要求它们都存在于内存中。您可能会发现接近统计数据的算法就足够了。
  2. 如果您的数据包含许多重复的字符串文字,请使用HashSet创建缓存。请注意,缓存因内存泄漏而臭名昭着(例如,在加载不同文件之前不清除它们)。
  3. 减少图表上显示的数据量。具有大量数据的图表通常在同一像素处或附近显示许多点。考虑通过在x轴上的相同位置处或附近合并多个值来截断数据。例如,如果您的数据集包含2,000,000个点,那么它们中的大多数将与其他附近点重合,因此您的基础数据模型不需要存储所有内容。
  4. 小心信息过载。如果JTable包含2GB数据,您的JTable是否对用户有意义?也许您应该对表进行分页,并且一次只能从文件中读取1000个条目以供显示。
  5. 我对此建议犹豫不决,但在加载过程中,您可以将CSV数据转换为文件数据库(例如cdb)。您可以在转换期间累积统计信息并存储图表的一些数据,并使用数据库按照上面的建议一次快速读取JTable的一页数据。