14

在我看到的从文件读取的每个 Java 实现中,我几乎总是看到一个文件读取器用于逐行读取。我的想法是,这将非常低效,因为它需要每行一个系统调用。

我一直在做的是使用输入流并直接获取字节。在我的实验中,这明显更快。我的测试是一个 1MB 的文件。

    //Stream method
    try {
        Long startTime = new Date().getTime();

        InputStream is = new FileInputStream("test");
        byte[] b = new byte[is.available()];
        is.read(b);
        String text = new String(b);
        //System.out.println(text);

        Long endTime = new Date().getTime();
        System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));

    }
    catch (Exception e) {
        e.printStackTrace();
    }

    //Reader method
    try {
        Long startTime = new Date().getTime();

        BufferedReader br = new BufferedReader(new FileReader("test"));
        String line = null;
        StringBuilder sb = new StringBuilder();
        while ((line = br.readLine()) != null) {
            sb.append(line);
            sb.append("\n");
        }
        String text = sb.toString();

        Long endTime = new Date().getTime();
        System.out.println("Text length: " + text.length() + ", Total time: " + (endTime - startTime));

    }
    catch (Exception e) {
        e.printStackTrace();
    }

这给出了以下结果:

Text length: 1054631, Total time: 9
Text length: 1034099, Total time: 22

那么,为什么人们使用阅读器而不是流呢?

如果我有一个方法可以获取一个文本文件并返回一个包含所有文本的字符串,那么使用流是否一定会更好?

4

3 回答 3

9

您正在将苹果与香蕉进行比较。即使使用缓冲读取器,一次读取一行的效率也会低于尽可能快地获取数据。请注意,不鼓励使用 available,因为它在所有情况下都不准确。当我开始使用密码流时,我自己发现了这一点。

于 2012-04-22T16:54:32.200 回答
3

FileReader通常与 a 一起使用,BufferedReader因为通常逐行读取文件是有意义的,特别是如果文件具有明确定义的记录结构,其中每条记录对应于一行。

此外,FileReader可以简化处理字符编码和转换的一些工作,如javadocs中所述:

读取字符文件的便利类。此类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的...... FileReader 用于读取字符流。

于 2012-04-22T16:49:09.450 回答
3

尝试增加BufferedReader缓冲区大小。例如:

BufferedReader br = new BufferedReader(new FileReader("test"),2000000);

如果您选择正确的缓冲区大小,您会更快。

然后在您的示例中与Reader您一起花时间填充 StringBuilder。如果需要处理行,则必须逐行读取文件。但是,如果您只需要读取字符串中的文本,那么读取更大的文本块public int read(char[] cbuf)并将这些块写入StringWriter具有适当大小的初始化。

选择使用InputStream与否Reader取决于性能。通常您Reader在阅读文本数据时使用,因为使用阅读器可以更轻松地处理字符集。

还有一点,你的代码在这里

byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);

这是不正确的。文档告诉_

请注意,虽然 InputStream 的某些实现会返回流中的字节总数,但许多不会。使用此方法的返回值来分配旨在保存此流中所有数据的缓冲区是不正确的。

所以要注意,你需要修复它。

于 2012-04-22T16:53:19.453 回答