Какой самый быстрый способ читать текстовый файл по очереди?
Я хочу прочитать текстовый файл по строкам. Я хотел бы знать, могу ли я сделать это как можно эффективнее в рамках .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 для чтения строк. Но чтение больших блоков и поиск вручную каждой новой строки в буфере чтения, вероятно, будет быстрее.