Как узнать количество строк в файле java

Обновлено: 03.07.2024

Это самая быстрая версия, которую я нашел, примерно в 6 раз быстрее, чем readLines. Для файла журнала объемом 150 МБ это занимает 0,35 секунды по сравнению с 2,40 секунды при использовании readLines(). Просто для удовольствия, команда linux 'wc -l занимает 0,15 секунды.

РЕДАКТИРОВАТЬ, 9 с половиной лет спустя: у меня практически нет опыта работы с Java, но в любом случае я пытался сравнить этот код с приведенным ниже решением LineNumberReader так как меня беспокоило, что никто этого не делал. Кажется, что особенно для больших файлов мое решение быстрее. Хотя кажется, что прогон несколько раз, пока оптимизатор не сделает достойную работу. Я немного поиграл с кодом и выпустил новую версию, которая является самой быстрой:

Результат теста для текстового файла 1,3 ГБ, ось Y в секундах. Я выполнил 100 прогонов с одним и тем же файлом и измерил каждый прогон с помощью System.nanoTime() . Вы можете видеть, что countLinesOld имеет несколько выбросов, а countLinesNew - нет, и хотя это только немного быстрее, разница статистически значима. LineNumberReader явно медленнее.

Benchmark Plot

Ответ 2

Я реализовал другое решение проблемы, я счел это более эффективным при подсчете строк:

Ответ 3

Принятый ответ имеет одну ошибку для нескольких строк файлов, которые не заканчиваются символом новой строки. Однострочный файл, заканчивающийся без новой строки, будет возвращать 1, но двухстрочный файл, заканчивающийся без новой строки, также будет возвращать 1. Здесь реализуется принятое решение, которое фиксирует это. КонцыWithoutNewLine проверки являются расточительными для всего, кроме окончательного чтения, но должны быть тривиальными по времени по сравнению с общей функцией.

Ответ 4

С java-8, вы можете использовать потоки:

Ответ 5

Ответ с помощью метода count() выше дал мне строки, если у файла не было новой строки в конце файла - ему не удалось подсчитать последнюю строку в файле.

Этот метод работает лучше для меня:

Ответ 6

Я знаю, что это старый вопрос, но принятое решение не совсем соответствовало тому, что мне было нужно. Таким образом, я уточнил, что он принимает различные терминаторы строк (а не только фиды строк) и использует заданную кодировку символов (а не ISO-8859- n). Все в одном методе (рефакторинг при необходимости):

Это решение сравнимо по скорости с принятым решением, примерно на 4% медленнее в моих тестах (хотя временные тесты на Java, как известно, ненадежны).

Ответ 7

Протестировано на JDK8_u31. Но на самом деле производительность медленная по сравнению с этим методом:

Протестировано и очень быстро.

Ответ 8

Я пришел к выводу, что метод подсчета строк wc -l : s хорош, но возвращает неинтуитивные результаты в файлах, где последняя строка не заканчивается символом новой строки.

И решение @er.vikas на основе LineNumberReader, но добавление одного к счету линии возвращает неинтуитивные результаты в файлах, где последняя строка заканчивается символом новой строки.

Поэтому я сделал algo, который обрабатывает следующее:

И это выглядит так:

Если вы хотите получить интуитивные результаты, вы можете использовать это. Если вам просто нужна совместимость wc -l , просто используйте решение @er.vikas, но не добавляйте его в результат и повторите прогон:

Ответ 9

Как насчет использования класса Process из кода Java? А затем прочитав вывод команды.

Нужно попробовать. Опубликуйте результаты.

Ответ 10

Прямой путь с помощью сканера

Ответ 11

Я проверил вышеупомянутые методы для подсчета строк, и вот мои наблюдения для различных методов, которые были проверены на моей системе

Размер файла: 1.6 Гб Методы:

  1. Использование сканера: около 35 с
  2. Использование BufferedReader: 5 с
  3. Использование Java 8: 5 с
  4. Использование LineNumberReader: 5 с

Ответ 12

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

Ответ 13

Это смешное решение работает действительно хорошо!

Ответ 14

В системах на базе Unix используйте команду wc в командной строке.

Ответ 15

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

Ответ 16

Лучший оптимизированный код для многострочных файлов, не имеющих символа новой строки ('\n') в EOF.

Узнайте, как найти количество строк в файле с помощью Java.

1. Обзор

В этом уроке мы узнаем, как найти количество строк в файле с помощью Java с помощью стандартных API ввода-вывода Java, Google Guava и библиотеки Apache Commons IO .

2. Файлы NIO2

Обратите внимание, что в этом руководстве мы будем использовать следующие примерные значения в качестве входного имени файла и общего количества строк:

Java 7 внесла множество улучшений в существующие библиотеки ввода-вывода и упаковала их под NIO2:

Давайте начнем с Files и посмотрим, как мы можем использовать его API для подсчета количества строк:

3. Файловый канал NIO

Теперь давайте проверим FileChannel, высокопроизводительную альтернативу Java NIO для чтения количества строк:

Хотя файловый канал был введен в JDK 4, приведенное выше решение работает только с JDK 7 или выше .

4. Файлы Google Guava

И тогда мы можем использовать readLines для получения Списка строк файла:

5. Файлы ввода-вывода Apache Commons

Теперь давайте посмотрим Apache Commons IO |/FileUtils API, параллельное решение Guava.

Чтобы использовать библиотеку, мы должны включить зависимость commons-io в pom.xml :

Как мы видим, это немного более подробно, чем решение Google Guava.

6. BufferedReader

Итак, как насчет старомодных способов? Если мы не находимся на JDK 7 и не можем использовать стороннюю библиотеку, у нас есть BufferedReader:

7. LineNumberReader

Или мы можем использовать LineNumberReader, прямой подкласс BufferedReader , который немного менее подробен:

Здесь мы вызываем метод skip , чтобы перейти к концу файла, и мы добавляем 1 к общему количеству строк , так как нумерация строк начинается с 0.

8. Сканер

И, наконец, если мы уже используем Scanner как часть более масштабного решения, это может решить проблему и для нас:

9. Заключение

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

Во многих редакторах при работе с текстовым документом вы можете видеть, сколько всего строк содержится в этом файле. Строки между собой разделяются символом перевода строки, который в каждой операционной системе (Windows, Unix, Mac) свой.

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

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

Вариант c LineNumberReader

public static long getLineCountByReader(String fileName) throws IOException <
try ( var lnr = new LineNumberReader( new BufferedReader( new FileReader(fileName)))) <
while (lnr.readLine() != null ) ;
return lnr.getLineNumber();
>
>

Сначала мы в конструкции try-with-resources последовательно создаём три Reader'a, оборачивая один в другой:

  1. FileReader - для работы с файлом.
  2. BufferedReader - для буферизации потока и ускорения обработки.
  3. LineNumberReader - собственно, для подсчёта количества строк.

Все перечисленные ридеры являются ресурсами и конструкция try-with-resources гарантирует нам, что после выхода из этого блока они все будут закрыты.

Затем в цикле вызываем у LineNumberReader метод readLine(). Поскольку никаких дополнительных действий нам делать не надо, то тело цикла будет пустым. После выхода из цикла метод getLineNumber() возвращает нам количество строк в файле.

На мой взгляд, это наиболее «читаемая» реализация, но ниже мы рассмотрим чуть более быструю версию. А пока можем вызвать наш метод:

public static void main(String[] args) throws IOException <
System.out.println( "Lines count: " + getLineCountByReader( "/home/user/very-large-file.txt" ));
>

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

Вариант c инкрементом

Наш метод можно немного ускорить, отказавшись от LineNumberReader. Вместо этого будем подсчитывать строки с помощью обычного инкремента.

public static long getLineCountByIncrement(String fileName) throws IOException <
var lines = 0L ;
try ( var reader = new BufferedReader( new FileReader(fileName))) <
while (reader.readLine() != null ) <
lines++;
>
return lines;
>
>

Здесь мы точно так же в блоке try создаём FileReader и BufferedReader, чтобы по окончании они были гарантированно закрыты. После этого в цикле на каждой итерации также вызываем метод readLine(). На этот раз тело цикла у нас не пустое, в нём мы увеличиваем переменную lines на 1. Такая реализация быстрее предыдущей примерно на 10%.

Это самая быстрая версия, которую я нашел, примерно в 6 раз быстрее, чем readLines. Для файла журнала объемом 150 МБ это занимает 0,35 секунды по сравнению с 2,40 секунд при использовании readLines (). Просто для удовольствия, команда linux 'wc -l занимает 0,15 секунды.

РЕДАКТИРОВАТЬ, 9 с половиной лет спустя: у меня практически нет опыта работы с Java, но в любом случае я пытался сравнить этот код с приведенным ниже решением LineNumberReader , поскольку меня беспокоило, что никто этого не делал. Кажется, что особенно для больших файлов мое решение быстрее. Хотя кажется, что прогон несколько раз, пока оптимизатор не сделает достойную работу. Я немного поиграл с кодом и выпустил новую версию, которая является самой быстрой:

Результаты теста производительности для текстового файла 1,3 ГБ по оси Y в секундах. Я выполнил 100 прогонов с одним и тем же файлом и измерил каждый прогон с помощью System.nanoTime() . Вы можете видеть, что countLinesOld имеет несколько выбросов, а countLinesNew - нет, и хотя это только немного быстрее, разница статистически значима. LineNumberReader явно медленнее.

Benchmark Plot

Я реализовал другое решение проблемы, я нашел его более эффективным при подсчете строк:

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

С Java-8 вы можете использовать потоки:

Ответ с помощью метода count (), приведенного выше, дал мне неправильные счета строк, если в файле не было новой строки в конце файла - он не смог посчитать последнюю строку в файле.

Этот метод работает лучше для меня:

Я знаю, что это старый вопрос, но принятое решение не совсем соответствовало тому, что мне было нужно. Итак, я усовершенствовал его, чтобы принимать различные разделители строк (а не просто перевод строки) и использовать указанную кодировку символов (а не ISO-8859-n). Все в одном методе (рефакторинг по необходимости):

Это решение сопоставимо по скорости с принятым решением, примерно на 4% медленнее в моих тестах (хотя временные тесты в Java общеизвестно ненадежны).

Протестировано на JDK8_u31. Но на самом деле производительность низкая по сравнению с этим методом:

Проверено и очень быстро.

Я проверил вышеупомянутые методы для подсчета линий, и вот мои наблюдения для различных методов, которые были проверены на моей системе

Размер файла: 1.6 Гб Методы:

  1. Использование сканера: 35 с
  2. с использованием BufferedReader: 5 с
  3. Используя Java 8: 5 с
  4. с использованием LineNumberReader: 5 с

Прямой путь с использованием сканера

Я пришел к выводу, что wc -l : s метод подсчета новых строк хорош, но возвращает неинтуитивные результаты для файлов, где последняя строка не заканчивается новой строкой.

И решение @ er.vikas, основанное на LineNumberReader, но добавив его к числу строк, дало неинтуитивные результаты для файлов, где последняя строка заканчивается символом новой строки.

Поэтому я сделал алгоритм, который обрабатывает следующим образом:

И это выглядит так:

Если вы хотите интуитивно понятные результаты, вы можете использовать это. Если вам нужна совместимость с wc -l , просто используйте решение @ er.vikas, но не добавляйте его к результату и повторите попытку:

Как насчет использования класса Process из кода Java? А затем читая вывод команды.


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

Мне было интересно, есть ли способ сделать это поумнее

Это самая быстрая версия, которую я нашел до сих пор, примерно в 6 раз быстрее, чем readLines. В файле журнала размером 150 МБ это занимает 0,35 секунды по сравнению с 2,40 секунды при использовании readLines (). Ради удовольствия, команда wc -l в linux занимает 0,15 секунды.

РЕДАКТИРОВАТЬ, 9 1/2 лет спустя: у меня практически нет опыта работы с java, но в любом случае я попытался сравнить этот код с решением ниже, поскольку меня беспокоило, что этого никто не делал. Кажется, что особенно для больших файлов мое решение работает быстрее. Хотя, кажется, потребуется несколько прогонов, пока оптимизатор не заработает нормально. Я немного поигрался с кодом и создал новую, неизменно самую быструю версию:

Результаты теста для текстового файла объемом 1,3 ГБ, ось Y в секундах. Я выполнил 100 прогонов с одним и тем же файлом и измерил каждый прогон с . Вы можете видеть, что имеет несколько выбросов, а не имеет ни одного, и хотя это только немного быстрее, разница статистически значима. явно медленнее.


  • 5 BufferedInputStream должен выполнять буферизацию за вас, поэтому я не понимаю, как использование промежуточного массива byte [] ускорит ее. В любом случае вы вряд ли добьетесь большего успеха, чем многократное использование readLine () (поскольку это будет оптимизировано для API).
  • 56 Вы собираетесь закрыть этот InputStream, когда закончите с ним, не так ли?
  • 5 Если бы буферизация помогла, это было бы, потому что BufferedInputStream по умолчанию буферизует 8 КБ. Увеличьте свой byte [] до этого или большего размера, и вы сможете отбросить BufferedInputStream. например попробуйте 1024 * 1024 байта.
  • 8 Две вещи: (1) Определение символа конца строки в исходном коде Java - это возврат каретки, перевод строки или возврат каретки, за которым следует перевод строки. Ваше решение не будет работать для CR, используемого в качестве ограничителя строки. Разумеется, единственная ОС, в которой, как мне кажется, в качестве ограничителя строки по умолчанию используется CR, является Mac OS до Mac OS X. (2) Ваше решение предполагает кодировку символов, такую ​​как US-ASCII или UTF-8. Счетчик строк может быть неточным для таких кодировок, как UTF-16.
  • 2 Потрясающий код . для текстового файла размером 400 мб, это заняло всего секунду. Большое спасибо @martinus

Я реализовал другое решение проблемы, счел более эффективным подсчет строк:

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

С java-8 вы можете использовать потоки:

  • 2 В коде есть ошибки. Просто, но очень медленно . Попробуйте посмотреть мой ответ ниже (вверху).

Ответ с помощью метода count () выше дал мне неправильный счет строк, если в файле не было новой строки в конце файла - он не смог подсчитать последнюю строку в файле.

Этот метод мне больше подходит:

Я знаю, что это старый вопрос, но принятое решение не совсем соответствовало тому, что мне нужно было сделать.Итак, я усовершенствовал его, чтобы принимать различные терминаторы строки (а не просто перевод строки) и использовать указанную кодировку символов (а не ISO-8859-п). Все в одном методе (при необходимости, рефакторинг):

Это решение сравнимо по скорости с принятым решением, примерно на 4% медленнее в моих тестах (хотя тесты времени в Java, как известно, ненадежны).

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

Размер файла: 1,6 Гб Методы:

  1. Использование сканера : Примерно 35 с
  2. Использование BufferedReader : Примерно 5 с
  3. Использование Java 8 : Примерно 5 с
  4. Использование LineNumberReader : Примерно 5 с

Кроме того Java8 Подход кажется весьма удобным:

Проверено на JDK8_u31. Но на самом деле производительность ниже по сравнению с этим методом:

Протестировано и очень быстро.

  • Это не так. Поэкспериментировал с вашим кодом, и этот метод всегда медленнее. Поток - Затрачено времени: 122796351 поток - Количество строк: 109808 Метод - Затраченное время: 12838000 Метод - Количество строк: 1 И количество строк тоже неверное
  • Я тестировал на 32-битной машине. Может на 64-битном были бы другие результаты .. А разница была раз в 10 и больше, насколько я помню. Не могли бы вы разместить где-нибудь текст для подсчета строки? Вы можете использовать Notepad2, чтобы видеть разрывы строк для удобства.
  • В этом может быть разница.
  • Если вы заботитесь о производительности, вам не следует использовать , когда вы все равно собираетесь читать в свой собственный буфер. Кроме того, даже если ваш метод может иметь небольшое преимущество в производительности, он теряет гибкость, так как он больше не поддерживает только терминаторы строки (старый MacOS) и не поддерживает все кодировки.

Простой способ использования сканера

Я пришел к выводу, что : s метод подсчета новых строк хорош, но возвращает неинтуитивно понятные результаты для файлов, где последняя строка не заканчивается новой строкой.

И решение @er.vikas на основе LineNumberReader, но добавление единицы к счетчику строк возвращало неинтуитивные результаты для файлов, где последняя строка заканчивается новой строкой.

Поэтому я сделал алгоритм, который обрабатывает следующее:

А это выглядит так:

Если вам нужны интуитивные результаты, вы можете использовать это. Если вам просто нужна совместимость с , просто используйте решение @ er.vikas, но не добавляйте его к результату и повторите попытку пропуска:

Как насчет использования класса Process из кода Java? А затем прочтите вывод команды.

Хотя нужно попробовать. Выложу результаты.

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

  • Похоже на отличную идею. Кто-нибудь пробовал это и для него есть регулярное выражение?
  • 1 Я сомневаюсь, что это такая хорошая идея: ему нужно будет прочитать весь файл сразу (Мартинус этого избегает), а регулярные выражения излишни (и медленнее) для такого использования (простой поиск фиксированных символов).
  • @will: а как насчет / \ n /? @PhiLo: Regex Executors - это хорошо настроенные рабочие машины. Я не думаю, что ручная реализация может быть быстрее, за исключением оговорки о том, что все в памяти читается.

Это забавное решение действительно хорошо работает!

Кажется, что есть несколько разных подходов, которые вы можете использовать с LineNumberReader.

Еще проще, вы можете использовать метод Java BufferedReader lines () для возврата потока элементов, а затем использовать метод Stream count () для подсчета всех элементов. Затем просто добавьте единицу к выходным данным, чтобы получить количество строк в текстовом файле.

В системах на базе Unix используйте команду в командной строке.

  • @IainmH, ваше второе предложение просто подсчитывает количество записей в текущем каталоге. Не то, что было задумано? (или по запросу OP)
  • @IainMH: это то, что делает wc в любом случае (чтение файла, считая окончания строки).
  • @PhiLho Вам нужно использовать ключ -l для подсчета строк. (Не так ли? - это было давно)
  • @Paul - ты конечно на 100% прав. Моя единственная защита - это то, что я разместил это перед кофе. Я сейчас сообразителен. : D

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

  • 1 Интересный отрицательный голос, независимо от того, какой инструмент командной строки вы используете, все они в любом случае ДЕЛАЮТ ОДНОВРЕМЕННОЕ, только внутренне. Волшебного способа подсчитать количество линий не существует, их приходится считать вручную. Конечно, это можно сохранить как метаданные, но это совсем другая история .

Читайте также: