【问题标题】:Quickest way to read text-file line by line in Java在 Java 中逐行读取文本文件的最快方法
【发布时间】:2011-08-13 14:37:29
【问题描述】:

对于日志处理,我的应用程序需要逐行读取文本文件。 首先我使用了 BufferedReader 的 readLine() 函数,但我在网上看到 BufferedReader 在读取文件时速度很慢。
之后我尝试将 FileInputStream 与 FileChannel 和 MappedByteBuffer 一起使用,但在这种情况下,没有类似于 readLine() 的函数,所以我在文本中搜索换行符并进行处理:

    try {
        FileInputStream f = new FileInputStream(file);
        FileChannel ch = f.getChannel( );
        MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0L, ch.size());
        byte[] bytes = new byte[1024];
        int i = 0;
        while (mb.hasRemaining()) {
            byte get = mb.get();
            if(get == '\n') {
                if(ra.run(new String(bytes)))
                    cnt++;
                for(int j = 0; j<=i; j++)
                    bytes[j] = 0;
                i = 0;
            }
            else
                bytes[i++] = get;
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

我知道这可能不是实现它的好方法,但是当我以字节为单位读取文本文件时,它比使用 BufferedReader 快 3 倍,但调用 new String(bytes) 创建一个新字符串并使程序变得更慢使用 BufferedReader 时。
所以我想问一下逐行读取文本文件的最快方法是什么?有人说 BufferedReader 是解决这个问题的唯一方法。

P.S.:ra 是 dk.brics.Automaton 库中 RunAutomaton 的一个实例。

【问题讨论】:

  • BufferedReader 真的太慢了​​,无法满足您的需求吗?如果您必须使用 Java 编码,它可能是最简洁、最可维护的解决方案之一。
  • 如果BufferedReader 对你的应用程序来说真的太慢了​​,你应该考虑不使用java或其他托管语言...... (但我怀疑是这种情况)
  • Aaron的答案作为一个链接的答案即将被删除,所以我将它作为评论放在这里:“检查this link out。它包含各种方法的速度比较。”

标签: java file-io readline text-files


【解决方案1】:

Using plain BufferedReader I got 100+ MB/s。您从磁盘读取数据的速度很可能是您的瓶颈,因此您如何进行读取不会有太大影响。

BufferedReader 不是唯一的解决方案,但它对于 99% 的用例来说已经足够快了,那么为什么要让事情变得比实际需要的更复杂呢?

【讨论】:

    【解决方案2】:

    我有一个非常简单的循环,它使用 BufferedReader 从 sdcard 上的文件中读取大约 2000 行(50k 字节),并在 Galaxy 选项卡 2 的调试模式下在大约 100 毫秒内读取它们。还不错。然后我在循环中放了一个扫描仪,时间飞逝(几十秒),加上很多 GC_CONCURANT 消息

    Scanner scanner = new Scanner(line);
    int eventType = scanner.nextInt(16);
    

    所以至少在我的情况下,问题在于扫描仪,我想我需要以另一种方式扫描整数,但我不知道为什么它会这么慢

    【讨论】:

      【解决方案3】:

      框架是替代品吗?

      我不知道性能,但是

      http://commons.apache.org/io/

      http://commons.apache.org/io/api-release/index.html见IOUtils类

      为此类情况定义了非常易于使用的辅助类。

      【讨论】:

        【解决方案4】:

        我非常怀疑BufferedReader 会导致大量开销。添加您自己的代码可能至少同样低效,而且很可能也是错误的。

        例如,在您给出的代码中,您调用new String(bytes),它总是会使用平台默认编码从 1024 字节创建一个字符串......这不是一个好主意。当然,之后你清除了数组,但你的字符串仍然会包含一堆 '\0' 字符——这意味着除了其他任何东西之外,还会浪费很多空间。您应该至少限制创建字符串的字节数组部分(这也意味着您无需在之后清除数组)。

        您是否真的尝试过使用BufferedReader 并发现它太慢了?您通常应该首先编写最简单的代码来满足您的目标,然后检查它是否足够快......特别是如果您不这样做的唯一原因是您“在互联网上阅读”的未指定资源。你想让我找到数百个提出不正确性能建议的人的例子吗? :)

        作为替代方案,您可能想查看GuavaFiles.readLines() 重载,它采用LineProcessor

        【讨论】:

        • 我已经尝试过 BufferedReader,它的性能很好,但是程序的要求是非常快,所以我只是想找出哪种解决方案对我的实施来说是最快的。
        • @Yoni:“非常快”是一个非常模糊的要求。您是否有任何证据表明瓶颈是 BufferedReader 而不是(更有可能)物理磁盘速度?
        • 如果我以字节为单位读取相同的文件,它比使用 BufferedReader 快 3 倍。我的硬盘速度约为 150mb/s,而我的程序读取速度为 30mb/s。
        • @Yoni:嗯……这有点令人惊讶。你使用什么编码,你的机器规格是什么?您是在调试器中运行,还是在做任何其他可能减慢它的事情?您是否完全使用字符串?
        • 我使用的是 windows-1258 编码,因为文件包含越南语字符。我正在使用字符串在其中找到一个正则表达式模式。它们被提供给 RunAutomaton 实例。我的机器规格:C2D P8700、4GB DDR2、HD:500GB(Sata2) 7200RPM。我没有在调试器中运行,也不是因为正则表达式它很慢,因为在评论 RunAutomaton 时读取速度相同。
        【解决方案5】:

        根据this SO 帖子,您可能还想试一试Scanner 课程。

        【讨论】:

          猜你喜欢
          • 2013-10-19
          • 2011-12-23
          • 2012-10-20
          • 1970-01-01
          • 1970-01-01
          • 2013-10-29
          • 1970-01-01
          • 2018-07-10
          相关资源
          最近更新 更多