【问题标题】:Using buffredReader read big files in java在java中使用buffredReader读取大文件
【发布时间】:2016-04-03 12:33:48
【问题描述】:

我知道在 java 中有两种读取大文本文件的方法。一种使用扫描仪,一种使用缓冲读取器。

Scanner reader = new Scanner(new FileInputStream(path));
while (reader.hasNextLine()){
    String tempString = reader.nextLine();
    System.out.println(java.lang.Runtime.getRuntime().totalMemory()/(1024*1024.0));
}

并且要打印的数字总是在某个值附近稳定。

但是,当我根据下面的编辑使用 bufferedReader 时,数字不稳定,它可能会在一行中突然增加(约 20mb),然后在多行(如 8000 行)中保持不变。并且该过程重复。 有谁知道为什么?

更新 我使用 BufferedReader 输入的第二种方法错误,应该是这样的

BufferedReader reader = new BufferedReader
    (new InputStreamReader(new FileInputStream(path)),5*1024*1024);
for(String s = null;(s=reader.readLine())!=null; ){
    System.out.println(java.lang.Runtime.getRuntime().totalMemory()/(1024*1024.0));
}

或者使用while循环

String s;
while ((s=reader.readLine())!=null ){
    System.out.println(java.lang.Runtime.getRuntime().totalMemory()/(1024*1024.0));
}

更具体地说,这里是测试用例读取 250M 文件的结果

扫描仪外壳:

行号---totolmemory
5000---117.0
10000---112.5
15000---109.5
20000---109.5
25000---109.5
30000---109.5
35000---109.5
40000---109.5
45000---109.5
50000---109.5

BufferedReader 案例:

行号---totolmemory
5000---123.0
10000---155.5
15000---155.5
20000---220.5
25000---220.5
30000---220.5
35000---220.5
40000---220.5
45000---220.5
50000---211.0

但是扫描仪很慢,所以我尽量避免它。

我检查了 bufferedReader 的情况,总内存在一个随机行中突然增加。

【问题讨论】:

  • 可能是BufferedReader后面的缓冲区管理...
  • 您的第二个循环是一个繁忙的循环,不断获取和打印总内存。它读取一行文本,然后不断循环。
  • 当您使BufferedReader 使用 5 MB 缓冲区时,您并没有真正将苹果与苹果进行比较。此外,您不会看到使用那么大的缓冲区的性能改进。您可以将该大小减小到 4 KB 或 16 KB,而不会降低性能。您将看到,BufferedReaderScanner很多,即使您只使用默认缓冲区大小。
  • totalMemory 与您(可能)尝试学习的内容完全无关。试试 freeMemory。
  • 谢谢大家,但我还是一头雾水,我不是想比较他们使用的内存,我只是想知道为什么使用bufferedReader的内存会增加,并且会突然增加一个随机行跨度>

标签: java


【解决方案1】:

就其本身而言,扫描仪并不是特别适合文本文件。

Scanner 和 BufferedReader 没有可比性。您可以在 Scanner 中使用 BufferedInputStream - 然后您将拥有相同的东西,Scanner 添加了更多的“流”读取功能而不仅仅是行。

查看 totalMemory 并不是特别有用。引用 Javadoc:返回 Java 虚拟机中的内存总量。此方法返回的值可能会随时间变化,具体取决于宿主环境。

试试 freeMemory,它更有趣一点,它反映了不时发生的 GC 阶段。

稍后 评论 Scanner 很慢:读取一行只需要扫描行分隔符的字节,这就是 BufferedReader 的工作方式。然而,Scanner 为这项任务启动了 java.util.regex.Matcher(因为它更适合其整体设计)。仅将扫描仪用于读取行数是在折腾。

【讨论】:

  • 是的,我知道 Scanner 和 BufferedReader 没有可比性。但我只想知道为什么使用扫描仪保持总内存稳定但使用 BufferedReader 保持总内存增加。如果文本文件超过 100GB,我仍然可以使用扫描仪,但它会超过缓冲读取器的内存
  • @ZheyuJi 不会的。使用您发布的代码,每一行都会被垃圾收集。 在尝试解决它之前,您应该确定您确实遇到了您担心的问题。很可能Scanner 在后台使用了BufferedReader
  • @EJP,谢谢,但趋势表明,如果您可以查看我更新的问题版本,总内存确实会增加。实际上,我确实在云计算中遇到了这个问题,当我使用扫描仪时,如果完全很好但很慢,当我使用 bufferedreader 时,它会超出内存。我的代码中的其他逻辑都是一样的。
  • ZheyuJi 您发布的数据没有出现这种趋势。没有内存不足的情况,20,000行后没有增加:而是完全稳定。使用 BufferedReader 可以每秒读取数百万行,而我已经这样做了很多次了
  • @EJP 谢谢,你是绝对正确的。它在我的本地机器上具有较大的文件是稳定的。但是云端测试还是显示超出内存,我必须每50000行添加System.gc()才能解决问题。无论如何我的主要问题已经解决了,我仍然需要一些时间来弄清楚为什么它会在云和没有 gc 的情况下失败
猜你喜欢
  • 2011-01-22
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
  • 2014-03-20
  • 1970-01-01
  • 2013-09-01
相关资源
最近更新 更多