就内存、处理器、时间而言,BufferInputReader 与 LineNumberReader 与 Java 中的 Stream 之间的最佳文件 Reader 是什么

What is Best File Reader in between BufferInputReader Vs LineNumberReader vs Stream in Java in terms of Memory, Processor, Time

我尝试了所有三个阅读过程,但无法判断哪个是最好的

内存利用率、处理器使用率、时间复杂度

我在网上看到了很多解决方案,但没有人对上述条款得出完美的结论。

我尝试了一些东西,请检查代码,让我知道如何在上面突出显示的要求中使其更加优化。

下面是我的代码。

注意:Out.txt 是 3Gb 文本文件

package Reader;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.LineNumberReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.stream.Stream;

/*
 *  Comparing Execution time of BufferInputReader Vs LineNumberReader Vs 
Stream
 *  o/p > Effeciency of BufferInputReader to LineNumberReader is around :: 
200%

 *  
 */
public class LineReaderBufferInputStream {

public static void main(String args[]) throws IOException {
    //LineReaderBufferInputStream
    LineReaderBufferInputStream lr = new LineReaderBufferInputStream();
    long startTime = System.nanoTime();

    int count = lr.countLinesUsingLineNumberReader("D://out.txt");

    long endTime = System.nanoTime();
    long c1 = (endTime - startTime);
    System.out.println(count + " LineReaderBufferInputStream Time taken:: " + c1);

    startTime = System.nanoTime();

    count = countLinesByBufferIpStream("D://out.txt");

    endTime = System.nanoTime();
    long c2 = (endTime - startTime);
    System.out.println(count + " BufferedInputStream Time taken:: " + c2);

    System.out.println("Effeciency of BufferInputReader to LineNumberReader is around :: " + (c1) / c2 * 100 + "%");

    // Java8 line by line reader
    //read file into stream, try-with-resources
    startTime = System.nanoTime();
    long cn = countLinesUsingStream("D://out.txt");
    endTime = System.nanoTime();

    System.out.println(cn +" Using Stream :: " + (endTime - startTime));

}

public int countLinesUsingLineNumberReader(String filename) throws IOException {
    LineNumberReader reader = new LineNumberReader(new FileReader(filename));
    int cnt = 0;
    String lineRead = "";
    while ((lineRead = reader.readLine()) != null) {
        //if you need to do anything with lineReader.
    }

    cnt = reader.getLineNumber();
    reader.close();
    return cnt;
}

public static int countLinesByBufferIpStream(String filename) throws IOException {
    InputStream is = new BufferedInputStream(new FileInputStream(filename));
    try {
        byte[] c = new byte[1024];
        int count = 1;
        int readChars = 0;
        boolean empty = true;
        while ((readChars = is.read(c)) != -1) {
            empty = false;
            for (int i = 0; i < readChars; ++i) {
                if (c[i] == '\n') {
                    ++count;
                }
            }
        }
        return (count == 0 && !empty) ? 1 : count;
    } finally {
        is.close();
    }
}

public static long countLinesUsingStream(String fileName) throws IOException{
    try (Stream<String> streamReader = Files.lines(Paths.get("D://out.txt"))) {

        return streamReader.count();

    } catch (IOException e) {
        e.printStackTrace();
    }
    return 0;
}

}

如果您问的是 类 中哪一个最快或使用最少的内存 通常 ,则没有答案。这在很大程度上取决于您正在执行的任务。以及您如何使用 类。

如果您要求最快的方法只是计算文件中的行数,那么最快的方法是使用InputStream直接读入ByteBuffer,然后计算行结束符。这也将使用最少的内存。

原因如下:

  • 任何为读取的每一行生成 String 的东西都将进行大量不必要的复制,并生成大量垃圾。
  • 任何使用 Reader 的东西都会将字节数据解码为字符数据。这包括 LineNumberReader
  • 如果使用 BufferedInputStream 并读入一个大的 byte[],你实际上是在做你自己的(简单的)缓冲。你也可以直接使用InputStream
  • 如果您使用 read(byte[]),则您正在将数据额外复制到 byte[]

有许多教程可以帮助您了解如何使用 ByteBuffer 快速 I/O。例如:


然而...

在涉及非常大文件的现实世界应用程序中,性能瓶颈经常被证明是文件系统和存储设备的性能,或者你如何处理数据来处理它......一旦你拥有它内存。

建议 避免优化应用程序的 I/O,直到更高级别的功能正常工作,并且能够编写 运行一个基准。然后您应该对应用程序进行概要分析以找出真正的瓶颈所在。最后,优化瓶颈。

除非您真的很有经验(即使您很有经验),否则您关于最佳花费优化工作的直觉通常是不正确的。


最后,计算文件行数的最快方法可能是忘记 Java 并使用标准的本机代码实用程序;例如在 Unix / Linux / MacOS 上使用 wc pathname.

备注:明确传递可移植文件的编码是好​​的,因为默认编码可能会有所不同。

Unicode 字符串的二进制文件数据的旧默认编码是平台编码。

较新的 Files.lines 将默认使用 UTF-8(万岁)。

这意味着 UTF-8 的转换速度稍慢,并且在错误的非 ASCII 字符上容易出错,因为 UTF-8 多字节序列需要正确的位格式。

  1. 一般来说 Files.lines 和其他像 Files.newBufferedReader 一样足够快。

  2. 对于大文件,可以使用 ByteBuffer/CharBuffer,一种通过 FileChannel 的内存映射文件。只需在网络上搜索即可。收获并不大

不转换,使用 (Buffered)InputStream / ByteBuffer,比转换为文本更快。

Java 将 (Unicode) 文本存储在字符串中作为 char 的 2 字节数组。最新的 java 也可以将其存储在单字节编码(jvm 选项)中,这可能会节省内存。

可能更好的方法是压缩文本,例如 Out.txt.gz。根据磁盘速度交易 CPU。