Самый быстрый способ чтения текстового файла по строкам в Java

Для обработки журналов мое приложение должно читать текстовые файлы по строкам. Сначала я использовал функцию readLine() BufferedReader, но я читал в Интернете, что BufferedReader работает медленно при чтении файлов.
Впоследствии я попытался использовать FileInputStream вместе с FileChannel и MappedByteBuffer, но в этом случае нет функции, аналогичной readLine(), поэтому я ищу свой текст для разрыва строки и обрабатываю его:

    try {
        FileInputStream f = new FileInputStream(file);
        FileChannel ch = f.getChannel( );
        MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, 0L, ch.size());
        byte[] bytes = new byte[1024];
        int i = 0;
        while (mb.hasRemaining()) {
            byte get = mb.get();
            if(get == '\n') {
                if(ra.run(new String(bytes)))
                    cnt++;
                for(int j = 0; j<=i; j++)
                    bytes[j] = 0;
                i = 0;
            }
            else
                bytes[i++] = get;
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

Я знаю, что это, вероятно, не лучший способ его реализовать, но когда я просто прочитал текстовый файл в байтах, он в 3 раза быстрее, чем при использовании BufferedReader, но вызов new String(bytes) создает новую строку и делает программу еще медленнее, чем при использовании BufferedReader.
Поэтому я хотел спросить, что является самым быстрым способом чтения текстового файла по строкам? Некоторые говорят, что BufferedReader - единственное решение этой проблемы.

P.S.: ra - это экземпляр RunAutomaton из библиотеки dk.brics.Automaton.

Ответ 1

Я очень сомневаюсь, что BufferedReader приведет к значительным накладным расходам. Добавление собственного кода скорее всего будет неэффективным и, возможно, неправильным.

Например, в коде, который вы указали, вы вызываете new String(bytes), который всегда будет создавать строку из 1024 байтов, используя стандартную кодировку платформы... не очень хорошая идея. Конечно, после этого вы очищаете массив, но ваши строки по-прежнему будут содержать кучу символов "\ 0", что означает много потерянного пространства, кроме всего прочего. Вы должны хотя бы ограничить часть массива байтов, из которой создается строка (что также означает, что вам не нужно очищать массив после этого).

Вы действительно пытались использовать BufferedReader и обнаружили, что он слишком медленный? Обычно вы должны написать простейший код, который сначала будет соответствовать вашим целям, а затем проверить, достаточно ли он... особенно, если ваша единственная причина не делать этого - это неуказанный ресурс, который вы "читаете в Интернете". Вы хотите, чтобы я нашел сотни примеров того, как люди неверно отзывались о предложениях?:)

В качестве альтернативы вы можете посмотреть Guava перегрузку Files.readLines(), которая принимает LineProcessor.

Ответ 2

Используя простой BufferedReader, я получил 100+ МБ/с. Весьма вероятно, что скорость, с которой вы можете прочитать данные с диска, - это бутылочная горловина, поэтому, как вы делаете чтение, не будет иметь большого значения.

BufferedReader - это не единственное решение, но оно достаточно быстро для 99% случаев использования, поэтому зачем делать вещи более сложными, чем они должны быть?

Ответ 3

Являются ли рамки альтернативой?

Я не знаю о производительности, но

http://commons.apache.org/io/

http://commons.apache.org/io/api-release/index.html См. класс IOUtils

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

Ответ 4

В соответствии с этой службой SO, вы также можете указать Scanner снимок класса.

Ответ 5

У меня очень простой цикл, который считывает около 2000 строк (50 тыс. байт) из файла на SD-карте с использованием BufferedReader, и он читает их все примерно в 100 мс в режиме отладки на вкладке галактики 2. Не так уж плохо. затем я поставил сканер в цикле и время прошло через крышу (десятки секунд), плюс множество сообщений GC_CONCURANT.

Scanner scanner = new Scanner(line);
int eventType = scanner.nextInt(16);

так что по крайней мере в моем случае это сканер, что проблема, я думаю, мне нужно сканировать ints по-другому, но я понятия не имею, почему это может быть так медленно