2009-08-14 4 views
49

У меня большой файл. Он включает приблизительно 3.000-20.000 линий. Как я могу получить общее количество строк в файле с помощью Java?Как я могу получить количество строк в файле эффективным способом?

+1

Судя по вашим комментариям к ответам, то слово, которое вы ищете «эффективный», а не «эффективные» , – AakashM

+0

Да, вы правы – firstthumb

+0

@Firstthumb: Пожалуйста, не удаляйте комментарии * после того, как люди ответили на них. Это заставляет поток запутывать людей, которые опаздывают на шоу. – Telemachus

ответ

84
BufferedReader reader = new BufferedReader(new FileReader("file.txt")); 
int lines = 0; 
while (reader.readLine() != null) lines++; 
reader.close(); 

Update: Чтобы ответить на производительность-вопрос, поставленный здесь, я сделал измерение. Первое: 20 000 строк слишком мало, чтобы программа работала в течение заметного времени. Я создал текстовый файл с 5 миллионами строк. Это решение (начатое с java без параметров, таких как -server или -XX-options), потребовалось около 11 секунд на моем ящике. То же самое с wc -l (командной строки UNIX для подсчета строк), 11 секунд. Решение, читающее каждый отдельный символ и ищущее «\ n», должно быть в 104 секунды, в 9-10 раз больше.

+0

Какую эффективность вы имеете в виду? Представление? В этом случае у вас не будет лучшего способа, потому что строки могут иметь разную длину, вам нужно будет прочитать полный файл, чтобы подсчитать номера строк (wc также делает это). Если вы говорите об эффективности программирования, то я уверен, что вы можете поместить его в утилиту-метод (или какая-то общая библиотека сделала это уже). – Mnementh

+0

@Firstthumb. Неэффективно, может быть, но кому это нужно. Он только считает 20k строк, что довольно мало. Этот код получает мой голос за то, что он самый простой. –

+0

Как насчет эффективности LineNumberReader, поскольку он расширяет BufferedReader? – Narayan

4

Прочитайте файл и подсчитайте количество символов новой строки. Простым способом чтения файла на Java, по одной строке за раз, является класс java.util.Scanner.

0

Прочитайте файл по строке и увеличьте счетчик для каждой строки, пока не прочитаете весь файл.

29

использование LineNumberReader

что-то вроде

public static int countLines(File aFile) throws IOException { 
    LineNumberReader reader = null; 
    try { 
     reader = new LineNumberReader(new FileReader(aFile)); 
     while ((reader.readLine()) != null); 
     return reader.getLineNumber(); 
    } catch (Exception ex) { 
     return -1; 
    } finally { 
     if(reader != null) 
      reader.close(); 
    } 
} 
+2

Возможно, вам также потребуется закрыть() читателя. –

+0

yup; done thanks: D – Narayan

+2

вы, вероятно, можете проверить читателя! = Null в блоке finally – dfa

-2

Буферизованные читатели излишества

Reader r = new FileReader("f.txt"); 

int count = 0; 
int nextchar = 0; 
while (nextchar != -1){ 
     nextchar = r.read(); 
     if (nextchar == Character.getNumericValue('\n')){ 
      count++; 
     } 
    } 

Моего поиска простого примера имеет createde один Thats на самом деле довольно беден. вызов read() повторяется для одного символа менее оптимальным. см. here для примеров и измерений.

+2

BufferedReader отлично справляется с различными строками. Ваше решение игнорирует окончания строки Mac ('\ r'). Это может быть хорошо. В любом случае, ваше решение фактически не читается в файле в данный момент. Я думаю, вы забыли линию. – Mnementh

+5

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

+0

. Это была идея; - Я хотел написать простейший возможный пример. Интересно, какая разница в скорости? – NSherwin

2

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

Извините, но у вас нет выбора. :-)

2

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

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

+0

+1 это может быть подходящий онлайн-алгоритм. – zeroin23

-1

Возможно, самым быстрым решением в чистой Java было бы чтение файла в виде байтов с использованием канала NIO в большой ByteBuffer. Затем, используя ваши знания схемы кодирования файла, подсчитайте закодированные CR и/или NL байты в соответствии с соответствующим соглашением разделителя строк.

Ключи для максимизации пропускной способности будет:

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

Реальный код слишком сложный для меня, чтобы писать «на лету». Кроме того, ОП не требует самого быстрого решения.

1

Попробуйте команду unix «wc». Я не имею в виду использовать его, я имею в виду загрузить источник и посмотреть, как они это делают. Вероятно, в c, но вы можете легко переносить поведение в java. Проблема с созданием собственного заключается в том, чтобы учесть проблему завершения cr/lf.

3

Это примерно так же эффективно, как он может получить, буферизованное бинарное чтение, нет строки преобразования,

FileInputStream stream = new FileInputStream("/tmp/test.txt"); 
byte[] buffer = new byte[8192]; 
int count = 0; 
int n; 
while ((n = stream.read(buffer)) > 0) { 
    for (int i = 0; i < n; i++) { 
     if (buffer[i] == '\n') count++; 
    } 
} 
stream.close(); 
System.out.println("Number of lines: " + count); 
2

Быстрых и грязный, но это делает работу:

import java.io.*; 

public class Counter { 

    public final static void main(String[] args) throws IOException { 
     if (args.length > 0) { 
      File file = new File(args[0]); 
      System.out.println(countLines(file)); 
     } 
    } 

    public final static int countLines(File file) throws IOException { 
     ProcessBuilder builder = new ProcessBuilder("wc", "-l", file.getAbsolutePath()); 
     Process process = builder.start(); 
     InputStream in = process.getInputStream(); 
     LineNumberReader reader = new LineNumberReader(new InputStreamReader(in)); 
     String line = reader.readLine(); 
     if (line != null) { 
      return Integer.parseInt(line.trim().split(" ")[0]); 
     } else { 
      return -1; 
     } 
    } 

} 
+0

Один побочный эффект, это решение не является перекрестной платформой. – Stephan

9

я нашел какое-то решение для этого он может пригодиться для вас

Ниже приведен фрагмент кода, подсчитайте количество строк из файла.

File file = new File("/mnt/sdcard/abc.txt"); 
    LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(file)); 
    lineNumberReader.skip(Long.MAX_VALUE); 
    int lines = lineNumberReader.getLineNumber(); 
    lineNumberReader.close(); 
+1

В результате строки 'count - 1' – MariuszS

+1

на самом деле результат' lines + 1' –

+0

Результат getLineNumber() плюс 1, потому что индекс строки начинается с 0 –

3

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

2

Это решение примерно на 3,6 × быстрее, чем самый высокий рейтинг при тестировании в файле с 13,8 миллионами строк. Он просто считывает байты в буфер и подсчитывает символы \n. Вы могли бы играть с размером буфера, но на моей машине ничего выше 8 КБ не делало код быстрее.

private int countLines(File file) throws IOException { 
    int lines = 0; 

    FileInputStream fis = new FileInputStream(file); 
    byte[] buffer = new byte[BUFFER_SIZE]; // BUFFER_SIZE = 8 * 1024 
    int read; 

    while ((read = fis.read(buffer)) != -1) { 
     for (int i = 0; i < read; i++) { 
      if (buffer[i] == '\n') lines++; 
     } 
    } 

    fis.close(); 

    return lines; 
} 
+0

. Интересно, будет ли использование предварительно скомпилированного шаблона RegEx сделать его быстрее или медленнее.Полагаю, что это будет делать со всеми окончаниями строк. И, я думаю, это может сделать это быстрее. – ingyhere

+0

Некоторые из вышеперечисленных решений могут воспользоваться буферизацией, а также, если это поможет. Например, «новый LineNumberReader (новый FileReader (theFilePathStr), 8096)» или что-то в этом роде. – ingyhere

+0

Будьте осторожны с символьными кодировками ... –

1

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

public static void main(String[] args) throws IOException { 
    File file = new File("yourfilehere"); 
    double fileSize = file.length(); 
    System.out.println("=======> File size = " + fileSize); 
    InputStream inputStream = new FileInputStream(file); 
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "iso-8859-1"); 
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader); 
    int totalRead = 0; 
    try { 
     while (bufferedReader.ready()) { 
      String line = bufferedReader.readLine(); 
      // LINE PROCESSING HERE 
      totalRead += line.length() + 1; // we add +1 byte for the newline char. 
      System.out.println("Progress ===> " + ((totalRead/fileSize) * 100) + " %"); 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
} 

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

[Редакция] Вот версия с расчетным временем. Я добавил SYSO, чтобы показать прогресс и оценку. Я вижу, что у вас хорошие ошибки оценки времени после того, как вы достаточно обработали линию (я стараюсь с 10-метровыми линиями, а после 1% лечения оценка времени была достоверной на уровне 95%). Я знаю, что некоторые значения должны быть установлены в переменной. Этот код быстро написан, но он полезен для меня. Надеюсь, это будет для вас тоже :).

long startProcessLine = System.currentTimeMillis(); 
    int totalRead = 0; 
    long progressTime = 0; 
    double percent = 0; 
    int i = 0; 
    int j = 0; 
    int fullEstimation = 0; 
    try { 
     while (bufferedReader.ready()) { 
      String line = bufferedReader.readLine(); 
      totalRead += line.length() + 1; 
      progressTime = System.currentTimeMillis() - startProcessLine; 
      percent = (double) totalRead/fileSize * 100; 
      if ((percent > 1) && i % 10000 == 0) { 
       int estimation = (int) ((progressTime/percent) * (100 - percent)); 
       fullEstimation += progressTime + estimation; 
       j++; 
       System.out.print("Progress ===> " + percent + " %"); 
       System.out.print(" - current progress : " + (progressTime) + " milliseconds"); 
       System.out.print(" - Will be finished in ===> " + estimation + " milliseconds"); 
       System.out.println(" - estimated full time => " + (progressTime + estimation)); 
      } 
      i++; 
     } 
    } finally { 
     bufferedReader.close(); 
    } 
    System.out.println("Ended in " + (progressTime) + " seconds"); 
    System.out.println("Estimative average ===> " + (fullEstimation/j)); 
    System.out.println("Difference: " + ((((double) 100/(double) progressTime)) * (progressTime - (fullEstimation/j))) + "%"); 

Не стесняйтесь улучшить этот код, если считаете, что это хорошее решение.

0

В моих тестах другие ответы берут ~ 150-300 мс в файле строки 118,5 тыс. Строк. Следующее занимает 1 мс, но является приблизительным (выводит строки 117 тыс. Строк) и зависит от того, что каждая строка имеет одинаковый размер.

private static void countSize(File file) { 
    long fileLength = file.length(); 
    BufferedReader reader = null; 
    try { 
    reader = new BufferedReader(new FileReader(file)); 
    //Skip header as it is of different size 
    reader.readLine(); 
    String text = reader.readLine(); 
    int lineLength = text.length(); 
    long lines = fileLength/lineLength; 
    System.out.println(lines); 
    } catch(IOException e) { 
    e.printStackTrace(); 
    } finally { 
    if(reader != null) { 
     try { 
     reader.close(); 
     } catch(IOException e) { 
     //no-op 
     } 
    } 
    } 
} 
13

Java 8+ имеет очень приятный и короткий путь, используя NIO:

Path path = Paths.get("./big_file.txt"); 
long lineCount = Files.lines(path).count(); 
+0

решение для спальни. у нас может быть проблема с charset – Mikhail

+1

charset UTF-8 по умолчанию –

Смежные вопросы