Определить количество строк в текстовом файле - PullRequest
191 голосов
/ 23 сентября 2008

Есть ли простой способ программно определить количество строк в текстовом файле?

Ответы [ 10 ]

366 голосов
/ 23 сентября 2008

Серьезно запоздалое редактирование: если вы используете .NET 4.0 или более позднюю версию

Класс File имеет новый метод ReadLines, который лениво перечисляет строки, а не жадно читает их все в массив, подобный ReadAllLines. Так что теперь вы можете иметь как эффективность и краткость с:

var lineCount = File.ReadLines(@"C:\file.txt").Count();

Оригинальный ответ

Если вы не слишком обеспокоены эффективностью, вы можете просто написать:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

Для более эффективного метода вы можете сделать:

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

Редактировать: В ответ на вопросы об эффективности

Причина, по которой я сказал, что второе было более эффективным, касалась использования памяти, а не обязательно скорости. Первый загружает все содержимое файла в массив, что означает, что он должен выделять как минимум столько же памяти, сколько размер файла. Вторая просто зацикливает одну строку за раз, поэтому ей никогда не нужно выделять больше памяти на одну строку за раз. Это не так важно для небольших файлов, но для больших файлов это может быть проблемой (например, если вы попытаетесь найти количество строк в файле 4 ГБ в 32-разрядной системе, например, там, где его просто недостаточно) адресное пространство пользовательского режима для выделения массива такого размера).

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

13 голосов
/ 23 сентября 2008

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

int lines = File.ReadAllLines("myfile").Length;
8 голосов
/ 23 сентября 2008

Это будет использовать меньше памяти, но, вероятно, займет больше времени

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();
5 голосов
/ 23 сентября 2008

Если под легким вы имеете в виду строки кода, которые легко расшифровать, но, скорее всего, неэффективны?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

Это, наверное, самый быстрый способ узнать, сколько строк.

Вы также можете сделать (в зависимости от того, буферизуете ли вы его)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}

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

2 голосов
/ 23 сентября 2008

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

1 голос

Чтение файла само по себе занимает некоторое время, сбор мусора в результате - еще одна проблема, так как вы читаете весь файл только для подсчета символов новой строки,

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

Нима Ара сделал хороший анализ, который вы могли бы принять во внимание

Вот предлагаемое решение, так как оно считывает 4 символа за раз, считает символ перевода строки и снова использует тот же адрес памяти для следующего сравнения символов.

private const char CR = '\r';  
private const char LF = '\n';  
private const char NULL = (char)0;

public static long CountLinesMaybe(Stream stream)  
{
    Ensure.NotNull(stream, nameof(stream));

    var lineCount = 0L;

    var byteBuffer = new byte[1024 * 1024];
    const int BytesAtTheTime = 4;
    var detectedEOL = NULL;
    var currentChar = NULL;

    int bytesRead;
    while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
    {
        var i = 0;
        for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 1];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 2];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 3];
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
                i -= BytesAtTheTime - 1;
            }
        }

        for (; i < bytesRead; i++)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
            }
        }
    }

    if (currentChar != LF && currentChar != CR && currentChar != NULL)
    {
        lineCount++;
    }
    return lineCount;
}

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

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

1 голос
/ 20 мая 2016

Жизнеспособным вариантом, который я лично использовал, было бы добавление собственного заголовка в первую строку файла. Я сделал это для пользовательского формата модели для моей игры. По сути, у меня есть инструмент, который оптимизирует мои файлы .obj, избавляя от ненужной мне ненужной ерунды, преобразует их в лучший макет, а затем записывает общее количество линий, граней, нормалей, вершин и текстурных UV-объектов самая первая строка. Эти данные затем используются различными буферами массива при загрузке модели.

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

1 голос
/ 23 сентября 2008

считать возврат каретки / перевод строки. Я верю в Unicode они все еще 0x000D и 0x000A соответственно. Таким образом, вы можете быть настолько эффективными или неэффективными, насколько захотите, и решить, должны ли вы иметь дело с обоими персонажами или нет

0 голосов
/ 07 октября 2012
try {
    string path = args[0];
    FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
    int i;
    string s = "";
    while ((i = fh.ReadByte()) != -1)
        s = s + (char)i;

    //its for reading number of paragraphs
    int count = 0;
    for (int j = 0; j < s.Length - 1; j++) {
            if (s.Substring(j, 1) == "\n")
                count++;
    }

    Console.WriteLine("The total searches were :" + count);

    fh.Close();

} catch(Exception ex) {
    Console.WriteLine(ex.Message);
}         
0 голосов
/ 23 сентября 2008

Вы можете запустить исполняемый файл " wc .exe" (поставляется с UnixUtils и не требует установки), запущенный как внешний процесс. Он поддерживает различные методы подсчета строк (например, Unix против Mac и Windows).

...