StreamReader. Readline () действительно самый быстрый метод, чтобы посчитать линии в файле?

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

For example these three:
c# how do I count lines in a textfile
Determine the number of lines within a text file
How to count lines fast?

Так, я шел вперед и закончил тем, что использовал то, что, кажется, является самым эффективным (по крайней мере, мудрый памятью?) метод, который я мог найти:

private static int countFileLines(string filePath)
{
    using (StreamReader r = new StreamReader(filePath))
    {
        int i = 0;
        while (r.ReadLine() != null) 
        { 
            i++; 
        }
        return i;
    }
}

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

Я пытался использовать StreamReader. Читайте() или StreamReader. Быстрый взгляд() , но я не могу (или не знать, как к), заставляют любого из них идти дальше к следующей строке, как только есть 'материал' (случайные работы? текст?).

Какие-либо идеи, пожалуйста?


CONCLUSION/RESULTS (After running some tests based on the answers provided):

Я проверил эти 5 методов ниже на двух различных файлах, и я получил последовательные результаты, которые, кажется, указывают что простой StreamReader. ReadLine() является все еще одним из самых быстрых путей... Честно говоря, я озадачен после всех комментариев и обсуждения в ответах.

File #1:
Size: 3,631 KB
Lines: 56,870

Results in seconds for File #1:
0.02 --> ReadLine method.
0.04 --> Read method.
0.29 --> ReadByte method.
0.25 --> Readlines.Count method.
0.04 --> ReadWithBufferSize method.

File #2:
Size: 14,499 KB
Lines: 213,424

Results in seconds for File #1:
0.08 --> ReadLine method.
0.19 --> Read method.
1.15 --> ReadByte method.
1.02 --> Readlines.Count method.
0.08 --> ReadWithBufferSize method.

Вот эти 5 методов, которые я проверил на основе всей обратной связи, которую я получил:

private static int countWithReadLine(string filePath)
{
    using (StreamReader r = new StreamReader(filePath))
    {
    int i = 0;
    while (r.ReadLine() != null)
    {
        i++;
    }
    return i;
    }
}

private static int countWithRead(string filePath)
{
    using (StreamReader _reader = new StreamReader(filePath))
    {
    int c = 0, count = 0;
    while ((c = _reader.Read()) != -1)
    {
        if (c == 10)
        {
        count++;
        }
    }
    return count;
    }            
}

private static int countWithReadByte(string filePath)
{
    using (Stream s = new FileStream(filePath, FileMode.Open))
    {
    int i = 0;
    int b;

    b = s.ReadByte();
    while (b >= 0)
    {
        if (b == 10)
        {
        i++;
        }
        b = s.ReadByte();
    }
    return i;
    }
}

private static int countWithReadLinesCount(string filePath)
{
    return File.ReadLines(filePath).Count();
}

private static int countWithReadAndBufferSize(string filePath)
{
    int bufferSize = 512;

    using (Stream s = new FileStream(filePath, FileMode.Open))
    {
    int i = 0;
    byte[] b = new byte[bufferSize];
    int n = 0;

    n = s.Read(b, 0, bufferSize);
    while (n > 0)
    {
        i += countByteLines(b, n);
        n = s.Read(b, 0, bufferSize);
    }
    return i;
    }
}

private static int countByteLines(byte[] b, int n)
{
    int i = 0;
    for (int j = 0; j < n; j++)
    {
    if (b[j] == 10)
    {
        i++;
    }
    }

    return i;
}
13
@John, ища \n и \r знаки.
добавлено автор Servy, источник
У каждой линии есть точно то же самое число байтов, или почти точно? Если they' ре, точное, вы могли просто посчитать размер файла, и если they' ре близко вы могли придумать близкое приближение на основе средней длины линии.
добавлено автор Servy, источник
Я обращался к комментарию относительно наличия скачка потока вперед
добавлено автор John, источник
как читал бы (), или быстрый взгляд() знают, где следующая строка находится в потоке?
добавлено автор John, источник
@Servy: Нет, длины варьируются по размеру и никогда не почти идентичны...
добавлено автор sergeidave, источник
@John: Спасибо, Джон. Ваш ответ (?) помогает мне понять I' m смотрящий в неправильном месте, даже если вы хотели его быть саркастичным.
добавлено автор sergeidave, источник

7 ответы

Нет, это не. Пункт - он осуществляет последовательности, который не необходим.

Чтобы ПОДСЧИТАТЬ его, вы очень более обеспечены, чтобы проигнорировать Часть "последовательности" и пойти Часть "линии".

ЛИНИЯ - ряд байтов, заканчивающихся \r\n (13, 10 - CR LF) или другой маркер.

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

9
добавлено
Если это не школа или другая домашняя работа стажера, вы неправы в программировании. Это - уровень "введения в программирование" теста.
добавлено автор TomTom, источник
Попытайтесь не читать байт байтом. Ассигнуйте буфер 128 КБ, прочитайте его, затем бегите вдоль него для работы возможно с небезопасным кодом указателя. Это относительно тривиально и должно обеспечить значительное повышение, возможно.
добавлено автор TomTom, источник
Распределение размера буфера помогает, хотя все еще близко к ReadLine (). Я обновил свой вход снова, чтобы добавить код, который я использовал там. Спасибо!
добавлено автор sergeidave, источник
Я попробую это, TomTom спасибо.
добавлено автор sergeidave, источник
TomTom, я запустил некоторые тесты и по-видимому мой исходный метод, Readline (), кажется, является самым быстрым. Я добавил свои примечания в мой оригинальный вопрос, в случае, если у вас была еще некоторая обратная связь на этом. Спасибо!
добавлено автор sergeidave, источник
Рассмотрение Brian' s пример кода и перечитывание вашего ответа заставляет меня понять what' s продолжение. Я также подозреваю, что, возможно, казался "неблагодарным", когда я сказал, что "Вы могли уточнить немного больше...?" Так как ваш ответ на самом деле объясняет вещи, я, вероятно, закончу тем, что выбрал его как ответ для этого вопроса. Спасибо, TomTom.
добавлено автор sergeidave, источник
Я предполагаю I' m на том уровне в этом отношении и мне don' t обижаются. I' m, не ища ' свободный lunch' здесь, я просто don' t как он, когда люди просто судят вас, не зная полную историю. Я действительно ценю ваш ' answer' и будет абсолютно использовать его для моего преимущества, в то время как я продолжаю пытаться понять это... с или без примера кода. Спасибо.
добавлено автор sergeidave, источник
Вы думаете, что это - школьная домашняя работа? C' понедельник...
добавлено автор sergeidave, источник
Вы могли уточнить немного больше с некоторым примером кода?Thank you!
добавлено автор sergeidave, источник

Лучший способ знать, как сделать это быстро, состоит в том, чтобы думать о самом быстром способе сделать это, не используя C/C++.

На собрании есть операция по уровню процессоров, которая просматривает память для характера так на собрании, вы сделали бы следующее

  • Рид большая часть (или все) файла в память
  • Выполняет команду SCASB
  • Повторение по мере необходимости

Так, в C# вы хотите, чтобы компилятор добрался максимально близко к этому.

5
добавлено

Я попробовал многочисленные методы и проверил их работу:

Тот, который читает единственный байт, приблизительно на 50% медленнее, чем другие методы. Другие методы все возвращение вокруг того же самого количества времени. Вы могли попытаться создать нити и сделать это асинхронно, поэтому в то время как вы ждете прочитанного, можно начать обрабатывать прочитанное предыдущее. Это походит на головную боль мне.

Я пошел бы с одним лайнером: Файл. ReadLines (filePath).Count (); это выступает, а также другие методы, которые я проверил.

        private static int countFileLines(string filePath)
        {
            using (StreamReader r = new StreamReader(filePath))
            {
                int i = 0;
                while (r.ReadLine() != null)
                {
                    i++;
                }
                return i;
            }
        }

        private static int countFileLines2(string filePath)
        {
            using (Stream s = new FileStream(filePath, FileMode.Open))
            {
                int i = 0;
                int b;

                b = s.ReadByte();
                while (b >= 0)
                {
                    if (b == 10)
                    {
                        i++;
                    }
                    b = s.ReadByte();
                }
                return i + 1;
            }
        }

        private static int countFileLines3(string filePath)
        {
            using (Stream s = new FileStream(filePath, FileMode.Open))
            {
                int i = 0;
                byte[] b = new byte[bufferSize];
                int n = 0;

                n = s.Read(b, 0, bufferSize);
                while (n > 0)
                {
                    i += countByteLines(b, n);
                    n = s.Read(b, 0, bufferSize);
                }
                return i + 1;
            }
        }

        private static int countByteLines(byte[] b, int n)
        {
            int i = 0;
            for (int j = 0; j < n; j++)
            {
                if (b[j] == 10)
                {
                    i++;
                }
            }

            return i;
        }

        private static int countFileLines4(string filePath)
        {
            return File.ReadLines(filePath).Count();
        }
4
добавлено
Большое спасибо за то, что заняли время, чтобы проверить это, Ника! Я запущу некоторые тесты с примерами, которые вы даете окончательно использованию, какой бы ни, кажется, более эффективен/быстр. Спасибо, снова!
добавлено автор sergeidave, источник
Ник, я добавил некоторые комментарии заключения к своему оригинальному вопросу на основе некоторых тестов, которые я запустил, используя большинство ваших предложенных методов, в случае, если вы хотели смотреть и имели больше обратной связи. Спасибо, снова!
добавлено автор sergeidave, источник
Да, файл, который я использовал, составлял намного большего 1 ГБ.
добавлено автор Nick Bray, источник

Да, чтение линий как этот является самым быстрым и самым легким путем в любом практическом смысле.

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

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

3
добавлено
Да, который является, почему я открыл высказывание его wouldn' t влияют на скорость.
добавлено автор Servy, источник
Обратите внимание что изменение wouldn' t быть так в скорости, но в объеме потребляемой памяти. Если линии - большой it' s различие между хранением каждой линии в памяти против только хранения одного характера за один раз в памяти (хотя с буферизованием, это won' t вполне иметь место, но это означает, что объем потребляемой памяти будет почти точно размером буфера, не больше).
добавлено автор Servy, источник
@Servy: Да, но это оказывает очень мало влияния на скорость.
добавлено автор Guffa, источник
public static int CountLines(Stream stm)
{
    StreamReader _reader = new StreamReader(stm);
    int c = 0, count = 0;
    while ((c = _reader.Read()) != -1)
    {
        if (c == '\n')
        {
            count++;
        }
    }
    return count;
}
3
добавлено
@500-InternalServerError OS и/или жесткий диск будут буферизовать его внутренне, you' ре вряд ли, чтобы видеть любые преимущества из буферизования его снова.
добавлено автор Servy, источник
@500-InternalServerError, Как вы были бы в состоянии сделать немного лучше? Я don' t видят любой возможный путь вокруг этого; лучшее, которое вы могли сделать, будет просто скрывать то, что некоторый API делает то же самое. У этого был бы меньший объем потребляемой памяти, чем OP с подобной работой, учитывая, что каждая линия довольно большая.
добавлено автор Servy, источник
@500-InternalServerError И почтительно, вы знаете мало о программировании тогда. Откройте поток файла - параметр для размера буфера. Или помещенный буферизированный поток вокруг этого.
добавлено автор TomTom, источник
У этого, вероятно, будет ужасная работа, называя метод для каждого характера в файле.
добавлено автор 500 - Internal Server Error, источник
@TomTom пробуют его за себя если вы don' t верят мне: версия, используя явный буфер и для петли будет по крайней мере вдвое более быстрой для больших файлов из-за чистого требования наверху reader.read.
добавлено автор 500 - Internal Server Error, источник
@Servy - Я почтительно не соглашаюсь, но допускаю, что различие может не иметь значения для OP.
добавлено автор 500 - Internal Server Error, источник
@Servy - Я, по крайней мере, использовал бы буфер и прочитал бы в это кусок за один раз. Другой подход должен был бы использовать отображение файла, но я должен все же попробовать это из.NET.
добавлено автор 500 - Internal Server Error, источник
@TomTom: Я вижу, что этот пример кода - в основном ответ, который вы опубликовали. Но ваш ответ объясняет what' s продолжение. Спасибо.
добавлено автор sergeidave, источник

Есть многочисленные способы прочитать файл. Обычно, , самые быстрые путь, являются самыми простыми:

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do what you gotta do here
        }
}

This page does a great performance comparison between several different techniques including using BufferedReaders, reading into StringBuilder objects, and into an entire array.

2
добавлено
Принцип K.I.S.S. в его самом прекрасном.
добавлено автор WorkRelated, источник

StreamReader is not the fastest way to read files in general because of the small overhead from encoding the bytes to characters, so reading the file in a byte array is faster.
The results I get are a bit different each time due to caching and other processes, but here is one of the results I got (in milliseconds) with a 16 MB file :

75 ReadLines 
82 ReadLine 
22 ReadAllBytes 
23 Read 32K 
21 Read 64K 
27 Read 128K 

В общем Файл. ReadLines должен быть немного медленнее, чем StreamReader. ReadLine петля. Файл. ReadAllBytes медленнее с большими файлами и бросит из исключения памяти с огромными файлами. Размер буфера по умолчанию для , FileStream является 4K, но на моей машине 64K, казался самым быстрым.

    private static int countWithReadLines(string filePath)
    {
        int count = 0;
        var lines = File.ReadLines(filePath);

        foreach (var line in lines) count++;
        return count;
    }

    private static int countWithReadLine(string filePath)
    {
        int count = 0;
        using (var sr = new StreamReader(filePath))      
            while (sr.ReadLine() != null)
                count++;
        return count;
    }

    private static int countWithFileStream(string filePath, int bufferSize = 1024 * 4)
    {
        using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
        {
            int count = 0;
            byte[] array = new byte[bufferSize];

            while (true)
            {
                int length = fs.Read(array, 0, bufferSize);

                for (int i = 0; i < length; i++)
                    if(array[i] == 10)
                        count++;

                if (length < bufferSize) return count;
            }
        }//end of using
    }

и проверенный с:

var path = "1234567890.txt"; Stopwatch sw; string s = "";
File.WriteAllLines(path, Enumerable.Repeat("1234567890abcd", 1024 * 1024 ));//16MB (16 bytes per line)

sw = Stopwatch.StartNew(); countWithReadLines(path)   ; sw.Stop(); s += sw.ElapsedMilliseconds + " ReadLines \n";
sw = Stopwatch.StartNew(); countWithReadLine(path)    ; sw.Stop(); s += sw.ElapsedMilliseconds + " ReadLine \n";
sw = Stopwatch.StartNew(); countWithReadAllBytes(path); sw.Stop(); s += sw.ElapsedMilliseconds + " ReadAllBytes \n";

sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 * 32); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 32K \n";
sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 * 64); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 64K \n";
sw = Stopwatch.StartNew(); countWithFileStream(path, 1024 *128); sw.Stop(); s += sw.ElapsedMilliseconds + " Read 128K \n";

MessageBox.Show(s);
0
добавлено
Microsoft Stack Jobs
Microsoft Stack Jobs
1 788 участник(ов)

Work & freelance only Microsoft Stack. Feed https://t.me/Microsoftstackjobsfeed Чат про F#: @Fsharp_chat Чат про C#: @CSharpChat Чат про Xamarin: @xamarin_russia Чат общения:@dotnettalks

Microsoft Developer Community Chat
Microsoft Developer Community Chat
584 участник(ов)

Чат для разработчиков и системных администраторов Microsoft Developer Community. __________ Новостной канал: @msdevru __________ Баним за: оскорбления, мат, рекламу, флуд, флейм, спам, NSFW контент, а также большое количество оффтоп тем. @banofbot