Я использую огромные файлы данных, иногда мне нужно знать только количество строк в этих файлах, обычно я открываю их и читаю их построчно, пока не достигну конца файла
Мне было интересно, если есть более разумный способ сделать это
источник
Я использую огромные файлы данных, иногда мне нужно знать только количество строк в этих файлах, обычно я открываю их и читаю их построчно, пока не достигну конца файла
Мне было интересно, если есть более разумный способ сделать это
Это самая быстрая версия, которую я нашел, примерно в 6 раз быстрее, чем readLines. Для файла журнала объемом 150 МБ это занимает 0,35 секунды по сравнению с 2,40 секунды при использовании readLines (). Ради интереса, команда linux 'wc -l занимает 0,15 секунды.
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
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();
}
}
РЕДАКТИРОВАТЬ, 9 с половиной лет спустя: у меня практически нет опыта работы с Java, но в любом случае я пытался сравнить этот код с приведенным LineNumberReader
ниже решением, так как меня беспокоило, что никто этого не делал. Кажется, что особенно для больших файлов мое решение быстрее. Хотя кажется, что прогон несколько раз, пока оптимизатор не сделает достойную работу. Я немного поиграл с кодом и выпустил новую версию, которая является самой быстрой:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
System.out.println(readChars);
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
Результат теста для текстового файла 1,3 ГБ, ось Y в секундах. Я выполнил 100 прогонов с одним файлом и измерил каждый прогон с помощью System.nanoTime()
. Вы можете видеть, что countLinesOld
имеет несколько выбросов, и не countLinesNew
имеет ни одного, и хотя это только немного быстрее, разница статистически значима. LineNumberReader
явно медленнее.
Я реализовал другое решение проблемы, я нашел его более эффективным при подсчете строк:
источник
LineNumberReader
«SlineNumber
поле представляет собой целое ... Не будет ли просто обернуть файлы больше чем Integer.MAX_VALUE? Зачем прыгать долго здесь?wc -l
подсчитывает количество символов новой строки в файле. Это работает, так как каждая строка заканчивается новой строкой, включая последнюю строку в файле. Каждая строка имеет символ новой строки, включая пустые строки, поэтому число символов новой строки == количество строк в файле. ТеперьlineNumber
переменная inFileNumberReader
также представляет количество увиденных символов новой строки. Он начинается с нуля до того, как будет найден какой-либо символ новой строки, и увеличивается с каждым увиденным символом новой строки. Так что не добавляйте один к номеру строки, пожалуйста.wc -l
и сообщается о файлах такого типа. Также см stackoverflow.com/questions/729692/...wc -l
вернет 1. Я пришел к выводу, что все методы имеют недостатки, и реализовал один из них на основе того, как я хотел бы, чтобы он себя вел, см. Мой другой ответ здесь.Принятый ответ имеет одну ошибку для многострочных файлов, которые не заканчиваются переводом строки. Файл с одной строкой, заканчивающийся без новой строки, вернул бы 1, но файл с двумя строками, заканчивающийся без новой строки, также вернул бы 1. Вот реализация принятого решения, которое исправляет это. Проверки endWithoutNewLine бесполезны для всего, кроме окончательного чтения, но должны быть тривиальными с точки зрения времени по сравнению с общей функцией.
источник
С участием Java-8Вы можете использовать потоки:
источник
Ответ с помощью метода count (), приведенного выше, дал мне неправильные счета строк, если в файле не было новой строки в конце файла - он не смог посчитать последнюю строку в файле.
Этот метод работает лучше для меня:
источник
cnt
.Я знаю, что это старый вопрос, но принятое решение не совсем соответствовало тому, что мне было нужно. Итак, я усовершенствовал его, чтобы принимать различные разделители строк (а не просто перевод строки) и использовать заданную кодировку символов (а не ISO-8859- n ). Все в одном методе (рефакторинг по необходимости):
Это решение сопоставимо по скорости с принятым решением, примерно на 4% медленнее в моих тестах (хотя временные тесты в Java, как известно, ненадежны).
источник
Я проверил вышеупомянутые методы для подсчета строк, и вот мои наблюдения для различных методов, которые были проверены на моей системе
Размер файла: 1.6 Гб Методы:
Более того, Java8- подход кажется довольно удобным:
источник
Проверено на JDK8_u31. Но на самом деле производительность медленная по сравнению с этим методом:
Проверено и очень быстро.
источник
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
И количество строк тоже неверноBufferedInputStream
когда вы все равно собираетесь читать в свой собственный буфер. Кроме того, даже если ваш метод может иметь небольшое преимущество в производительности, он теряет гибкость, так как он больше не поддерживает\r
терминаторы единственной строки (старые MacOS) и не поддерживает все кодировки.Прямой способ использования сканера
источник
Я пришел к выводу, что
wc -l
: s метод подсчета новых строк хорош, но возвращает неинтуитивные результаты для файлов, где последняя строка не заканчивается новой строкой.И решение @ er.vikas, основанное на LineNumberReader, но добавив его к числу строк, дало неинтуитивные результаты для файлов, где последняя строка заканчивается новой строкой.
Поэтому я сделал алгоритм, который обрабатывает следующим образом:
И это выглядит так:
Если вы хотите интуитивно понятные результаты, вы можете использовать это. Если вам нужна
wc -l
совместимость, просто используйте решение @ er.vikas, но не добавляйте одно к результату и повторите попытку:источник
Как насчет использования класса Process из Java-кода? А затем читая вывод команды.
Нужно попробовать это все же. Опубликуем результаты.
источник
Если у вас нет структур индекса, вы не сможете обойтись без чтения всего файла. Но вы можете оптимизировать его, избегая читать его построчно и использовать регулярное выражение для сопоставления со всеми разделителями строк.
источник
Это забавное решение работает очень хорошо на самом деле!
источник
В системах на основе Unix используйте
wc
команду в командной строке.источник
Единственный способ узнать, сколько строк в файле - это подсчитать их. Конечно, вы можете создать метрику из ваших данных, которая даст вам среднюю длину в одну строку, а затем получить размер файла и разделить его с помощью avg. длина, но это не будет точно.
источник
Лучший оптимизированный код для многострочных файлов, не имеющих символа новой строки ('\ n') в EOF.
источник
Сканер с регулярным выражением:
Не разобрались в этом.
источник
если вы используете это
Вы не можете запускать строки с большим числом, любит 100K строк, потому что return от reader.getLineNumber - int. Вам нужен длинный тип данных для обработки максимального количества строк.
источник
int
Может содержать значения до, приблизительно, 2 млрд. Если вы загружаете файл с более чем 2 миллиардами строк, у вас есть проблема переполнения. Тем не менее, если вы загружаете неиндексированный текстовый файл с более чем двумя миллиардами строк, у вас, вероятно, есть другие проблемы.