Какой самый быстрый способ читать текстовый файл по очереди?

Я хочу прочитать текстовый файл по строкам. Я хотел бы знать, могу ли я сделать это как можно эффективнее в рамках .NET С#.

Это то, что я пытаюсь сделать до сих пор:

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}

Ответ 1

Если вы используете .NET 4, просто используйте File.ReadLines, который делает все это для вас. Я подозреваю, что это так же, как и ваш, за исключением того, что он может также использовать FileOptions.SequentialScan и больший буфер (128 кажется очень маленьким).

Ответ 2

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

Использование StreamReader.ReadLine

Это в основном ваш метод. По какой-то причине вы задаете размер буфера наименьшим возможным значением (128). Это приведет к увеличению производительности. Размер по умолчанию - 1024, а другие хорошие варианты - 512 (размер сектора в Windows) или 4096 (размер кластера в NTFS). Для определения оптимального размера буфера вам нужно будет запустить тест. Больший буфер - если не быстрее - по крайней мере, не медленнее, чем меньший буфер.

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
      // Process line
  }

Конструктор FileStream позволяет указать FileOptions. Например, если вы читаете большой файл последовательно от начала до конца, вы можете воспользоваться FileOptions.SequentialScan. Опять же, бенчмаркинг - лучшее, что вы можете сделать.

Использование File.ReadLines

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

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

Использование File.ReadAllLines

Это очень похоже на предыдущий метод, за исключением того, что этот метод увеличивает список строк, используемых для создания возвращаемого массива строк, поэтому требования к памяти выше. Однако он возвращает String[], а не IEnumerable<String>, позволяющий случайным образом получать доступ к строкам.

var lines = File.ReadAllLines(fileName);
foreach (var line in lines)
  // Process line

Использование String.Split

Этот метод значительно медленнее, по крайней мере, в больших файлах (проверен на файл размером 511 КБ), вероятно, из-за того, как реализовано String.Split. Он также выделяет массив для всех строк, увеличивающих требуемую память по сравнению с вашим решением.

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

Мое предложение - использовать File.ReadLines, потому что он чист и эффективен. Если вам нужны специальные параметры совместного доступа (например, вы используете FileShare.ReadWrite), вы можете использовать свой собственный код, но вы должны увеличить размер буфера.

Ответ 3

Хотя File.ReadAllLines() является одним из простейших способов чтения файла, он также является одним из самых медленных.

Если вы просто хотите читать строки в файле, не делая многого, в соответствии с этими критериями, самый быстрый способ прочитать файл - это старый метод:

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do minimal amount of work here
        }
}

Однако, если вам нужно делать много с каждой строкой, то в этой статье делает вывод, что лучший способ является следующим (и быстрее назначить строку [], если вы знаете, сколько строк вы собираетесь читать):

AllLines = new string[MAX]; //only allocate memory here

using (StreamReader sr = File.OpenText(fileName))
{
        int x = 0;
        while (!sr.EndOfStream)
        {
               AllLines[x] = sr.ReadLine();
               x += 1;
        }
} //Finished. Close the file

//Now parallel process each line in the file
Parallel.For(0, AllLines.Length, x =>
{
    DoYourStuff(AllLines[x]); //do your work here
});

Ответ 4

Используйте следующий код:

var lines = File.ReadAllLines(fileName);
foreach (var line in lines)

Это была огромная разница в производительности чтения.

Он идет за счет потребления памяти, но полностью стоит!

Ответ 5

Если размер файла невелик, быстрее читать весь файл, а затем разделять строку:

var filestreams = sr.ReadToEnd().Split("\r\n".ToCharArray(), 
                              StringSplitOptions.RemoveEmptyEntries);

Ответ 6

Там хорошая тема об этом в вопросе Возвращается ли доходность "медленнее, чем возвращение" старой школы"?.

В нем говорится:

ReadAllLines загружает все строки в память и возвращает Строка []. Все хорошо и хорошо, если файл небольшой. Если файл больше, чем поместится в памяти, вы исчерпаете память.

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

Скажем, вы хотели найти первую строку, содержащую слово "foo", а затем выйти. Используя ReadAllLines, вам нужно будет прочитать весь файл в память, даже если "foo" встречается в первой строке. С ReadLines, вы читаете только одну строку. Какой из них будет быстрее?

Ответ 7

Если вы нацелены на скорость выполнения, да, вы. Код может быть короче с помощью конструктора StreamReader.

Ответ 8

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

Ответ 9

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