【问题标题】:Optimize Scanner performance for large files优化大文件的扫描仪性能
【发布时间】:2013-01-16 11:28:55
【问题描述】:

我用Java 编写了一个程序,使用Scanner 来获取每行用空格分隔的两个元素,然后将其放入ArrayList 中存储的对象中。它工作得很好,但是当涉及到 10000 行的输入时,它会变得很长。我阅读了一些主题和网站(例如this)告诉BufferedReader 会比Scanner 高效很多,但我在尝试时没有看到任何改进。

这是我目前用来解析输入的每一行的行:

  String charsetName = "UTF-8";
  Scanner scanner = new Scanner(new BufferedInputStream(System.in), charsetName);

然后我在调用的行数期间运行了一个循环:

 String[] mid = scanner.nextLine().split(" ");

所以我尝试将Scanner 替换为:

BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] base = reader.readLine().split(" ");

它没有改变任何东西(两种情况下 12000 行 8 秒)

我是否朝着正确的方向前进以使程序更快地运行?还是问题出在使用循环遍历每一行?

【问题讨论】:

  • 你能举个例子吗?
  • 所以你想把每一行的二维数组放到ArrayList中?
  • 我注意到,无论我在循环中放入什么,只要有“String[] val =scanner.nextLine().split(”“);”,就需要 8 秒阅读 12000 行,其他任何东西都可以在不到 1 秒的时间内完成。
  • 在我使用字符串拆分的答案中查看下面的代码。这对你有影响吗?
  • 起初完全误读了您的问题。我以为你正在阅读一个非常大的文件,所以 8 秒可能是现实的。显示示例行确实很有用。

标签: java performance optimization split buffer


【解决方案1】:

我使用以下代码读取了一个 280,000 行(每行由空格分隔的两个单词组成)的文件,并将它们拆分为一个空格。 耗时 0.105 秒。所以我想更多地了解你正在解析的行以及你正在用它做什么。请粘贴更多代码。

  public static void main(String args[]) throws Exception {

    Date start = new Date();

    BufferedReader b = new BufferedReader(new FileReader("aa.txt"));
    String line;
    while ((line = b.readLine())!=null) {
      String[] splat = line.split(" ");
    }
    b.close();

    Date end = new Date();
    System.out.println("Took " + (end.getTime() - start.getTime()) / 1000.0 + " seconds");
  }

我修改了上面的代码,将每个 splat 数组添加到数组列表中(不确定你为什么要这样做,但我猜这就是你想要做的,来自你的 OP)。代码减慢到 0.244 秒。仍然不到一秒钟。请提供更多信息。

补充 - 完整代码(使用 javac Julien.java 编译)。 记得用你的文件名替换 aa.txt。

import java.util.*;
import java.io.*;

public class Julien {

  public static void main(String args[]) throws Exception {

    Date start = new Date();
//    List arrl = new ArrayList();
    BufferedReader b = new BufferedReader(new FileReader("aa.txt"));
    String line;
    while ((line = b.readLine())!=null) {
      String[] splat = line.split(" ");
//      arrl.add(splat);
    }
    b.close();
    Date end = new Date();
    System.out.println("Took " + (end.getTime() - start.getTime()) / 1000.0 + " seconds");
  }
}

【讨论】:

  • 到目前为止,我正在做一些非常简单的测试,以找出延迟的来源: Scanner scanner = new Scanner(new BufferedInputStream(System.in)); int a = 12000; // 我输入的行数,无论如何我都会指定它 for(int i=0;i
  • @Julien “我尝试了你的代码 xagyg,但它从未完成编译。”好吧,你需要把它放在一个类中,你需要import java.io.*; import java.util.*; 在顶部。如果你愿意,我可以发布整个课程。 您还需要将 aa.txt 替换为您的文件名或在本地文件系统中创建 aa.txt。 让我知道您有什么问题。它使用简单的 javac YourClassName 编译。
  • 在重新启动或后续运行后第一次运行时为 0.105 秒。对如此少量数据进行磁盘缓存可以消除所有磁盘访问。
  • @xagyg 您的代码在使用外部输出时可以完美运行,但是您知道我应该如何修改“while ((line = b.readLine())!=null) {” 以使其工作与系统输入?当我将缓冲区配置为读取输入时,它永远不会结束。再次感谢!
  • 你试过这个...BufferedReader b = new BufferedReader(new InputStreamReader(System.in)); 另外,你如何使用标准输入(管道或文件到你的程序,或手动输入)?
猜你喜欢
  • 1970-01-01
  • 2011-12-21
  • 1970-01-01
  • 1970-01-01
  • 2019-07-19
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多