Что такое лучшее средство чтения файлов между BufferInputReader и LineNumberReader против Stream в Java с точки зрения памяти, процессора, времени - PullRequest
0 голосов
/ 03 апреля 2019

Я попробовал все три процесса чтения, но не могу судить, что лучше всего с точки зрения

Использование памяти, использование процессора, сложность времени

Я видел много решений в Интернетено никто не пришел к идеальному выводу на вышеуказанных условиях.

Я мало что пробовал, пожалуйста, проверьте код и дайте мне знать, как сделать его более оптимизированным в вышеуказанном требовании.

Нижемой код.

ПРИМЕЧАНИЕ. 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;
}

}

Ответы [ 2 ]

1 голос
/ 03 апреля 2019

Если вы спрашиваете, какой из этих классов является самым быстрым или использует наименьшее количество памяти в общем , то ответа нет. Это критически зависит от задачи, которую вы выполняете. А как вы используете классы.

Если вы запрашиваете самый быстрый способ просто подсчитать строки в файле, то самым быстрым способом будет использование InputStream для чтения непосредственно в ByteBuffer, а затем подсчитайте строку терминаторы. Это также будет использовать наименьшее количество памяти.

И вот почему:

  • Все, что генерирует String для каждой прочитанной строки, будет выполнять много ненужного копирования и создавать много мусора.
  • Все, что использует Reader, будет выполнять декодирование байтовых данных в символьные данные. Это включает в себя LineNumberReader
  • Если вы используете BufferedInputStream и читаете большой byte[], вы фактически делаете свою собственную (простую) буферизацию. Вы также можете использовать InputStream напрямую.
  • Если вы используете read(byte[]), вы делаете дополнительную копию данных в byte[].

Существует ряд руководств, которые помогут вам понять, как использовать ByteBuffer для быстрого ввода-вывода. Например:

  • Страница учебного пособия по Java NIO Buffer в учебном пособии по Java на Jenkov.com.

Однако ...

В реальных приложениях, использующих действительно большие файлы, узким местом в производительности часто оказывается производительность файловой системы и запоминающих устройств или то, что вы делаете с данными для их обработки ... как только они попадают в память.

Рекомендуется , чтобы не оптимизировать ввод-вывод вашего приложения до тех пор, пока у вас не заработает функциональность более высокого уровня, и вы не сможете написать и запустить тест. Затем вы должны профилировать приложение, чтобы найти узкие места на самом деле. Наконец, оптимизация узких мест.

Если вы действительно не опытны (и часто даже если не имеете), ваши инстинкты о том, куда лучше всего потратить усилия по оптимизации, часто бывают неверными.


Наконец, самый быстрый способ подсчета строк в файле - это, вероятно, забыть о Java и использовать стандартную утилиту для собственного кода; например в Unix / Linux / MacOS используйте wc pathname.

0 голосов
/ 03 апреля 2019

Одно замечание: хорошо явно передавать кодировку переносимого файла, поскольку кодировка по умолчанию может различаться.

Более старой кодировкой по умолчанию для двоичных данных файла в Unicode String была кодировка платформы.

Более новый 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.Торговый процессор против скорости диска.

...