繁体   English   中英

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

[英]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的转换速度要慢一些,而且由于UTF-8多字节序列需要正确的位格式,因此错误的非ASCII字符容易出错。

  1. 通常, Files.lines和其他文件(例如Files.newBufferedReader足够快。

  2. 对于大文件,可以使用ByteBuffer / CharBuffer,这是通过FileChannel进行的内存映射文件。 只需在网上搜索。 收益不是很大。

使用(Buffered)InputStream / ByteBuffer进行不转换比转换为文本要快。

Java将(Unicode)文本作为2个字节的char数组存储在String中。 最新的Java可以替代地也将其存储为单字节编码(jvm选项),这可以节省内存。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM