【问题标题】:What's the fastest way in Java to count lines starting with a String in a huge fileJava中以字符串开头的大文件中计算行的最快方法是什么
【发布时间】:2017-08-15 01:03:15
【问题描述】:

我有很大的文件(每个 4.5 GB),需要计算每个文件中以给定标记开头的行数。每个文件最多可以出现 20 万次令牌。

实现如此庞大的文件遍历和字符串检测的最快方法是什么?有没有比使用ScannerString.startsWith() 的以下实现更有效的方法?

public static int countOccurences(File inputFile, String token) throws FileNotFoundException {
    int counter = 0;
    try (Scanner scanner = new Scanner(inputFile)) {
        while (scanner.hasNextLine()) {
            if (scanner.nextLine().startsWith(token)) {
                counter++;
            }
        }
    }
    return counter;
}

注意:

  • 到目前为止,Scanner 似乎是瓶颈(即,如果我添加比令牌检测更复杂的处理并将其应用于所有行,则总体执行时间或多或少相同。)
  • 我使用的是 SSD,所以硬件方面没有改进的余地

提前感谢您的帮助。

【问题讨论】:

  • 普通!它不是重复的,您是否阅读过您所指的问题?我说的是有数百万行而不是 20k 的文件,我也在谈论令牌检测。您的“重复”标签仅表明您没有阅读我的问题,也没有阅读您所指的问题。
  • 问题已结束,我无法将其作为答案发布,但请看一下 grep does that 的方法。它避免使用Boyer–Moore search algorithm 读取每个字节。
  • 我也不认为这是重复的。这怎么没有标记?
  • 阅读:nadeausoftware.com/articles/2008/02/…。如果你想你可以用 ByteBuffer.allocateDirect 读取大块将节省从文件读取的时间,你可以并行分配数据的过程来搜索你的令牌和换行符
  • grep | wc -l ?

标签: java performance file file-io


【解决方案1】:

几个指针(假设行比较短,数据真的是ASCII或类似的):

  • 一次读取一个巨大的字节缓冲区(例如 1/4 GB),然后切断不完整的行以添加到下一次读取之前。

  • 搜索字节,不要浪费时间转换为字符

  • 指示“以'\n'开始搜索模式的行首,特别对待第一行

  • 使用以牺牲预处理为代价减少搜索时间的高速搜索(谷歌表示“快速子字符串搜索”)

  • 如果需要实际的行号(而不是行数),请在单独的阶段计算行数

【讨论】:

  • 这就是我最终要做的。有关信息,当使用 100MB 缓冲区和 Boyer-Moore 搜索算法时,总执行时间从 16 分钟下降到 1 分钟。现在它是一个近似值,因为我仍然必须检测被分成两部分的令牌,但是即使在最坏的情况下,我也错过了不到 0.025% 的我正在寻找的事件......这对于现在来说已经足够精确了。谢谢!
【解决方案2】:

我们可以将问题简化为在字节流中搜索\n<token>。在这种情况下,一种快速的方法是从磁盘顺序读取一大块数据(大小根据经验确定,但一个好的起点是 1024 页),然后将该数据交给不同的线程进行处理。

【讨论】:

  • 小心跨越块边界的\n<token>序列。
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 2013-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-05
  • 2014-08-27
相关资源
最近更新 更多