Есть ли какие-либо приемы для подсчета количества строк в текстовом файле? [закрытый]

Необходимо проверить Контракты Кода ; они делают в значительной степени точно, что Вы спрашиваете. Пример:

[Pure]
public static double GetDistance(Point p1, Point p2)
{
    CodeContract.RequiresAlways(p1 != null);
    CodeContract.RequiresAlways(p2 != null); 
    // ...
}

8
задан xyz 9 October 2009 в 07:25
поделиться

7 ответов

Возможно, не самый быстрый, но он будет наиболее универсальным ...

int lines = 0;
/* if you need to use an encoding other than UTF-8 you way want to try...
   new StreamReader("filename.txt", yourEncoding) 
   ... instead of File.OpenText("myFile.txt")
*/
using (var fs = File.OpenText("myFile.txt"))
    while (!fs.EndOfStream)
    {
        fs.ReadLine();
        lines++;
    }

... это, вероятно, будет быстрее ...

если вам нужно еще больше скорости, вы можете попробовать a устройство Даффа и проверьте 10 или 20 байтов перед ветвью

int lines = 0;
var buffer = new byte[32768];
var bufferLen = 1;    
using (var fs = File.OpenRead("filename.txt"))
    while (bufferLen > 0)
    {
        bufferLen = fs.Read(buffer, 0, 32768);
        for (int i = 0; i < bufferLen; i++)
            /* this is only known to work for UTF-8/ASCII other 
               file types may need to search for different End Of Line 
               characters */                
            if (buffer[i] == 10)           
                lines++;
    }
11
ответ дан 3 November 2019 в 13:09
поделиться

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

Теперь наиболее эффективным будет способ Райниера - подсчет окончаний строк вручную. Однако самый простой код будет использовать TextReader.ReadLine () . И на самом деле, самый простой способ сделать это - использовать мой класс LineReader из MiscUtil , который преобразует имя файла (или другие вещи) в IEnumerable . Затем вы можете просто использовать LINQ:

int lines = new LineReader(filename).Count();

(Если вы не хотите получать всю MiscUtil, вы можете получить только LineReader самостоятельно из этого ответа .)

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

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

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

РЕДАКТИРОВАТЬ: преобразовать ответ Мэтью в ответ, который будет работать для любой кодировки, но который повлечет за собой штраф за декодирование всего данные, конечно, вы можете получить что-то вроде кода ниже. Я' m предполагая, что вы только заботитесь о \ n , а не \ r , \ n и \ r \ n , который TextReader обычно обрабатывает:

public static int CountLines(string file, Encoding encoding)
{
    using (TextReader reader = new StreamReader(file, encoding))
    {
        return CountLines(reader);
    }
}

public static int CountLines(TextReader reader)
{
    char[] buffer = new char[32768];

    int charsRead;
    int count = 0;

    while ((charsRead = reader.Read(buffer, 0, buffer.Length)) > 0)
    {
        for (int i = 0; i < charsRead; i++)
        {
            if (buffer[i] == '\n')
            {
                count++;
            }
        }
    }
    return count;
}
10
ответ дан 3 November 2019 в 13:09
поделиться

Если это фиксированная запись, вы можете получить размер записи и затем разделить весь файл size на эту сумму, чтобы получить количество записей. Если вы просто ищете оценку, то, что я делал в прошлом, просто прочитал первые x строк (например, 200) и использовал это, чтобы придумать средний размер строки, который вы затем можете использовать, чтобы угадать общее число записей (общий размер файла разделите на средний размер строки). Это хорошо работает, если ваши записи будут достаточно единообразными и вам не нужен точный подсчет. Я'

5
ответ дан 3 November 2019 в 13:09
поделиться

Я бы прочитал его по 32 КБ за раз (или больше), подсчитал количество \ r \ n в блоке памяти и повторял, пока не закончил.

3
ответ дан 3 November 2019 в 13:09
поделиться

Самый простой:

int lines = File.ReadAllLines(fileName).Length;

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

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

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

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

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

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

2
ответ дан 3 November 2019 в 13:09
поделиться

Я считаю, что Windows использует два символа для обозначения конца строки (10H и 13H, если я правильно помню), поэтому вам нужно только сравнивать каждый второй символ с этими двумя.

1
ответ дан 3 November 2019 в 13:09
поделиться

Поскольку это чисто последовательный процесс без зависимостей между местоположениями, рассмотрите возможность map / reduce, если объем данных действительно велик. В C / C ++ вы можете использовать OpenMP для параллелизма. Каждый поток будет читать фрагмент и подсчитывать CRLF в этом фрагменте. Наконец, в части сокращения они суммируют свои индивидуальные подсчеты. Блоки Intel Threading Building Blocks предоставляют вам конструкции на основе шаблонов C ++ для параллелизма. Я согласен, что это подход кувалды для небольших файлов, но с точки зрения чистой производительности он оптимален (разделяй и властвуй)

1
ответ дан 3 November 2019 в 13:09
поделиться