Самый быстрый способ читать текстовые файлы построчно в Java - PullRequest
7 голосов
/ 27 апреля 2011

Для обработки логов мое приложение должно читать текстовые файлы построчно.Сначала я использовал функцию 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 является единственным решением этой проблемы.

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

Ответы [ 5 ]

19 голосов
/ 27 апреля 2011

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

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

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

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

2 голосов
/ 27 апреля 2011

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

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

1 голос
/ 27 апреля 2011

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

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

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

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

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

0 голосов
/ 28 января 2013

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

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

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

0 голосов
/ 27 апреля 2011

В соответствии с этой ТАКОЙ публикацией вы также можете попробовать класс Сканер .

...