【问题标题】:Fastest way to load huge text file into a int array将大型文本文件加载到 int 数组中的最快方法
【发布时间】:2016-12-28 10:03:03
【问题描述】:

我有一个大文本文件 (+100MB),每一行都是一个整数(包含 1000 万个数字)。当然,大小和数量可能会发生变化,所以我事先不知道。

我想将文件加载到int[],以尽可能快地处理。首先我想到了这个解决方案:

public int[] fileToArray(String fileName) throws IOException
{
    List<String> list = Files.readAllLines(Paths.get(fileName));
    int[] res = new int[list.size()];
    int pos = 0;
    for (String line: list)
    {
        res[pos++] = Integer.parseInt(line);
    }
    return res;
}

速度非常快,5.5 秒。其中,readAllLines 调用耗时 5.1s,循环耗时 0.4s。

但后来我决定尝试使用 BufferedReader,并得出了这个不同的解决方案:

public int[] fileToArray(String fileName) throws IOException
{
    BufferedReader bufferedReader = new BufferedReader(new FileReader(new File(fileName)));
    ArrayList<Integer> ints = new ArrayList<Integer>();
    String line;
    while ((line = bufferedReader.readLine()) != null)
    {
        ints.add(Integer.parseInt(line));
    }
    bufferedReader.close();

    int[] res = new int[ints.size()];
    int pos = 0;
    for (Integer i: ints)
    {
        res[pos++] = i.intValue();
    }
    return res;
}

这甚至更快! 3.1 秒,while 循环只需 3 秒,for 循环甚至不到 0.1 秒。

我知道这里没有太多优化空间,至少在时间上是这样,但使用 ArrayList 然后使用 int[] 对我来说似乎内存太多了。

关于如何加快速度或避免使用中间 ArrayList 的任何想法?

为了比较,我用 FreePascal 在 1.9 秒内完成了同样的任务 [见编辑],使用 TStringList 类和 StrToInt 函数。

编辑:由于我使用 Java 方法的时间很短,所以我必须改进 FreePascal 方法。 330~360ms。

【问题讨论】:

  • 看起来您已经收集了一些好的指标。你可能想看看stackoverflow.com/questions/13155700/…
  • 你可以试试这个 ArrayList ints = new ArrayList(); Integer[] res = ints.toArray(new Integer[ints.size()]);
  • 你能通过获取文件大小来估计文件中整数的数量吗?您可以将它作为构造函数中的初始容量传递给 ArrayList,也许它不需要增长这么多次。
  • @WW。我试过了,没有明显区别。
  • 你的 FreePascal 是否使用 Unicode(Java 内部确实使用了一种 UTF-16,因此每个 char 占用两个字节;Java 9 将为 latin-1 字符串提供更紧凑的编码)?在 Java 中,Strings 是一流的对象,这是有一定成本的。 +++ 你的平台编码是什么?使用new InputStreamReader(new FileInputStream(...), encoding) 可能会加快速度。

标签: java arrays performance


【解决方案1】:

如果您使用的是 Java 8,则可以通过使用 lines() 然后映射到 int,然后将值收集到一个数组中来消除这个中间 ArrayList

您还应该使用try-with-resources 进行正确的异常处理和自动关闭。

try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
    return br.lines()
             .mapToInt(Integer::parseInt)
             .toArray();
}

我不确定这是否更快,但它肯定更容易维护。

编辑:它显然要快得多。

【讨论】:

  • 如果@mclopez 能给我们一些关于这个解决方案的性能信息,我会很感兴趣。
  • @mclopez 如果对您的研究有帮助,这里使用的功能是Streams 和方法参考。您还应该研究 lambda 表达式。
猜你喜欢
  • 2021-06-21
  • 2011-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2011-01-24
  • 2021-09-25
  • 1970-01-01
相关资源
最近更新 更多