Чтение больших файлов без нагрузки на память c#

183
19 сентября 2018, 11:40

Есть большой текстовой файл (несколько гигов), нужно рассмотреть каждую строку не тратя много памяти.

Пытался так :

Parallel.ForEach(File.ReadLines(path), opt, a => { Fil(a); opt.CancellationToken.ThrowIfCancellationRequested(); });

но память постепенно загружается. В методе Fil() я использую регулярное выражение.

Пытался и так

using (FileStream fs = File.Open(accpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
    using (BufferedStream bs = new BufferedStream(fs))
    {
        using (StreamReader sr = new StreamReader(bs))
        {
            string line;
            while ((line = sr.ReadLine()) != null)
            {
                Fil(line);
            }
        }
    }
}

Эффект тот же, есть ли возможность не нагружать память вообще ?

Answer 1

Начну с конца...
Второй вариант - самый плохой, так как он использует BufferedStream. Тем самым, вы создаете еще один дополнительный буфер в памяти. По факту, у вас весь считанный файл будет находиться в оперативной памяти.

Первый вариант - зачем вы используете параллельное чтение? Замените ваш параллельный вариант на последовательный, чтобы более точно контролировать количество загруженных строк в память

foreach(var line in File.ReadLines(filePath))
{
     Fil(line);
}

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

Стоит отметить еще такой момент, что .Net Runtime память освобождает по необходимости. Память в приложении может не освобождаться, если GC посчитает, что так будет более оптимально для работы приложения. Зачем ему отдавать память, если он уже ее взял и ее никто не просит у него, если она может ему потребоваться в скором времени?

GС(сборщик мусора) срабатывает, когда

  1. В системе мало оперативной памяти
  2. Количество выделенной памяти для управляемых объектов превысил порог.Этот порог непрерывно корректируется по мере запуска процесса.
  3. Вызывается явно метод GC.Collect2 для ручного запуск сборки "мусора". Почти во всех случаях вам не нужно вызывать этот метод, потому что сборщик мусора работает непрерывно. Этот метод в основном используется для уникальных ситуаций и тестирования.
Answer 2

Начнем с этого.

Parallel.ForEach(File.ReadLines(path), opt, a => { Fil(a); opt.CancellationToken.ThrowIfCancellationRequested(); });

Параллельное чтение из файла? Как вы себе это представляете?

Давайте кое что поясним:

1) Чтение с диска - медленная операция
2) Чем меньше чтений диска, тем лучше
3) Оперативная память не бесконечная

То есть, оптимальное чтение с диска в вашем случае - чтение с буфером.

Как читать с буфером?

using(var bufferedFileStream = 
  new BufferedStream(File.OpenRead(path), 1024*1024)) // буфер в мегабайт
{
  ....
}

Внутри этой конструкции можете считывать так, как вам понравится. Хотите StreamReader? Оберните это всё в него и все дела

using(var reader = 
    new StreamReader(
        new BufferedStream(File.OpenRead(path), 1024*1024) // буфер в мегабайт
        ))
{
  ....
}

так как чтение у вас будет однопоточное, то вам не надо морочиться с синхронизацией. Никаких конструкций lock дальше вам ставить не надо.

READ ALSO
pyinstaller failed to execute script

pyinstaller failed to execute script

Расклад такой, у меня есть программа на c# она подгружает нужные файлы для работы другой программы на pythonТакие параметры pyinstaller -F --noconsole, программа...

152
C# + SQLite. Вопрос для знающих [закрыт]

C# + SQLite. Вопрос для знающих [закрыт]

Всем привет, у меня вопросЯ тут пишу программку на c#, что-то вроде AIMP (просто для практики) и мне знакомый программист сказал что бы я использовал...

169
Трудности с отправкой данных на сервер в MVC .Net

Трудности с отправкой данных на сервер в MVC .Net

Начальная цель - отправить данные, введенные в форме на сервер, и, если данные верны, выдать соответствующую страницу, если же нет - перезагрузить...

169
Что такое инвариант в ООП?

Что такое инвариант в ООП?

Очень часто в статьях по ООП встречается такое слово, как инвариант:

180