【问题标题】:Reading a text file using BufferedReader.readLine() is too slow使用 BufferedReader.readLine() 读取文本文件太慢
【发布时间】:2013-05-29 07:28:39
【问题描述】:

我正在尝试读取一个包含大约 1000 行很长的文本文件。整个文件大约为 1.4MB。 我正在使用 BufferedReader 的 readLine 方法来读取文件。发生的情况是在控制台上打印输出需要 8-10 秒。我使用 php 的 fgets 尝试了相同的操作,它在眨眼之间打印了所有相同的行!!!这怎么可能? 下面是我正在使用的代码

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ClickLogDataImporter {
    public static void main(String [] args) {
        try {
            new ClickLogDataImporter().getFileData();
        } catch (Exception ex) {
            Logger.getLogger(ClickLogDataImporter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void getFileData() throws FileNotFoundException, IOException {
        String path = "/home/shantanu/Documents";
        BufferedReader br = new BufferedReader(new InputStreamReader(
                new FileInputStream(path+"/sample.txt")));
        String line = "";
        while((line = (br.readLine())) != null) {
            System.out.println(line);
        }

    }
}

PHP 代码

<?php
    $fileName = "/home/shantanu/Documents/sample.txt";
    $file = fopen($fileName, 'r');
    while(($line = fgets($file)) != false) {
        echo $line."\n";
    }
?>

请教我这个问题

【问题讨论】:

  • 请检查修改后的代码。正如 DJon 正确解释的那样,我正在做两个无与伦比的过程。逐行阅读和转储整个内容是两件不同的事情。所以我执行了另一个测试,现在使用 fgets。结果还是一样
  • 我认为,这两个程序的运行方式相同,也是从命令行运行的?
  • 在命令行上都可以
  • 好的,那么,你从什么时候开始测量时间?我在代码中没有看到。所以问题可能在于 JRE 加载时间,而不是代码的执行时间。
  • 好的,当我注释掉控制台输出时。 java大约需要80-90ms,php不超过5ms!我仔细检查了它。但就是这样

标签: java php io


【解决方案1】:

我不确定,但我认为 PHP 只是根据您使用的方法打印文件,Java 读取文件并从中获取每一行,这意味着检查每个字符是否有换行符,该过程似乎不是完全一样。

string file_get_contents

如果您尝试使用 PHP 从文件中逐行打印,它应该会更慢。

【讨论】:

  • 请检查修改后的代码。现在我在 php 中使用了 fgets。因此,一一阅读所有行。结果没有变化
  • 您是从浏览器还是 shell 中使用 PHP?那么一定是你的控制台输出,去掉System.out.printl(line),看看需要多长时间。
  • 我都从 shell 运行。
  • 如果你能提供示例文件,或者告诉我们大小和行数,我可以测试这两种方法并告诉你我是否有相同的结果。
  • 共有 1000 行,每行至少 1000 个字符长
【解决方案2】:

8 秒的代码对我来说听起来太多太长了。老实说,我怀疑发生了其他事情。您确定不是控制台输出需要很长时间吗?

我建议您计时(例如使用System.nanoTime)在最后写出总时间,但在最小化控制台的情况下运行它。我怀疑你会发现它已经足够快了。

【讨论】:

  • 两个代码都是控制台上的打印行。还是 php 在跳动!
  • @Shades88:也许 PHP 出于某种原因有更快的控制台访问。我非常怀疑阅读文件所花费的时间。这很容易测试。如果您摆脱 Java 中的控制台输出 - 例如,只需计算您读取的行并在最后写出该计数 - 需要多长时间?
  • 我进行了同样的测试。评论控制台输出,java 需要 80-90ms 然而,php 只需要 3-5ms!!
  • @Shades88:我的猜测是,这取决于操作系统缓存......和 ​​JIT 编译。您可能会发现,如果您多次运行该方法,它会非常快。这个程序是否真的代表了您正在尝试做的任何事情,或者您只是想比较 PHP 和 Java 的速度?如果是这样,这不是一个非常有用的比较 IMO。
【解决方案3】:

不就是控制台输出很慢吗?既然您知道您的文件已正确读取,请尝试注释掉 System.out.println(line); 行。

【讨论】:

    【解决方案4】:

    file_get_contents 将所有文件内容加载到一个字符串中,您的 Java 代码正在逐行读取和打印。 如果您在 Eclipse 之类的 IDE 中进行测试,控制台输出可能会很慢。 如果你想要 file_get_contents 的确切行为,你可以使用这个脏代码:

     File f = new File(path, "sample.txt");
     ByteArrayOutputStream bos = new ByteArrayOutputStream(new Long(Math.min(Integer.MAX_VALUE, f.length())).intValue());
     FileInputStream fis = new FileInputStream(f);
     byte[] buf = new byte[1024 * 8];
     int size;
     while((size = fis.read(buf)) > 0) {
        bos.write(buf, 0, size);
     }
     fis.close();
     bos.close();
     System.out.println(new String(bos.toByteArray()));
    

    【讨论】:

      【解决方案5】:

      好吧,如果您使用 readline,它将为每行读取文件 1000 次。尝试使用具有非常大缓冲区的读取功能,例如超过 28000 左右。然后它将读取一个文件,说总共 60 次 1.4 MB 远小于 1000。如果您使用 1000 的小缓冲区,那么它将读取大约 1300 或什至比 1000 慢的文件(readline) .此外,在打印行时,请使用 print 而不是 println,因为这些行并不完全是行,而是一个字符数组。

      【讨论】:

        【解决方案6】:

        阅读器通常很慢,您应该尝试快速的流阅读器。并确保文件打开过程不需要时间。如果打开文件并创建流对象然后测量时间,那么您可以确切地确定这是由于文件打开问题或读取文件问题。确保执行此操作时系统io负载不高,否则您的测量会变坏。

         BufferedInputStream reader=new BufferedInputStream(new FileInputStream("/home/shantanu/Documents/sample.txt"));
         byte[] line=new byte[1024];
         while(reader.read(line)>0) {
         System.out.println(new String(line));
         }
        

        【讨论】:

        • 这仍然在做同样的工作——将二进制数据转换为文本数据——只是在不同的点。此外,建议将InputStream 用于文本数据基本上是一个坏主意。例如,您的代码最终可能会读取字符的 part(例如,使用 UTF-8 的两字节字符的第一个字节),而您永远不会知道。更重要的是,您的代码不使用read 的返回值,因此您正在使用整个缓冲区创建一个字符串,无论它是否充满了有用的数据。
        猜你喜欢
        • 2011-08-01
        • 2023-04-05
        • 1970-01-01
        • 1970-01-01
        • 2016-07-14
        • 2016-10-06
        • 1970-01-01
        • 2012-05-08
        • 1970-01-01
        相关资源
        最近更新 更多