Ошибка нехватки памяти при архивировании файла журнала
У меня проблема с консольным заданием, которое запускается и создает ежедневный файл журнала, который я архивирую в полночь.
Это создает пустой файл журнала на следующий день и архивированный файл с вчерашней датой в названии и содержимым старого файла для устранения проблем, которые у меня могли возникнуть и о которых я не знал до следующего дня.
Однако с тех пор, как я приступил к работе с BOT, у меня возникали проблемы с ошибками системной нехватки памяти при попытке заархивировать файл.
Сначала я просто не мог получить заархивированный файл, затем я разработал способ получить по крайней мере последние 100000 строк, что недостаточно.
Заворачиваю все в 3 попытки / ловит
- I/O
- Системе не хватает памяти
- стандартное исключение
Однако это всегда OutOfMemoryException, которое я получаю, например
System.OutOfMemoryException Ошибка: было сгенерировано исключение типа "System.OutOfMemoryException".;
Чтобы дать вам пример размером 100000 строк журнала составляет около 11 МБ файла
Стандартный полный файл журнала может быть от 1/2 ГБ до 2 ГБ.
Что мне нужно знать, это:
а) какой размер стандартного текстового файла приведет к ошибке "недостаточно памяти" при попытке использовать File.ReadAllText или пользовательскую функцию StreamReader, которую я вызываю ReadFileString, например
public static string ReadFileString(string path)
{
// Use StreamReader to consume the entire text file.
using (StreamReader reader = new StreamReader(path))
{
return reader.ReadToEnd();
}
}
б) это память моего компьютера (у меня 16 ГБ ОЗУ - 8 ГБ во время копирования) или объекты, которые я использую в C#, которые не работают с открытием и копированием файлов.
При архивировании я сначала пытаюсь использовать свою пользовательскую функцию ReadFileString (см. Выше), если она возвращает 0 байт содержимого, я пытаюсь использовать File.ReadAllText, а затем, если это не удается, я пытаюсь использовать пользовательскую функцию для получения последних 100000 строк, чего на самом деле недостаточно для ошибки отладки в начале дня.
Файл журнала начинается в полночь, когда создается новый, и регистрируется весь день. У меня никогда не было ошибок нехватки памяти, но с тех пор, как я увеличил частоту вызовов методов, журналирование расширилось, что означает, что размер файлов также увеличился.
Это моя пользовательская функция для получения последних 100000 строк. Мне интересно, сколько строк я мог бы получить без ИТ, из-за которого не хватало памяти, и я вообще не получил никакого содержимого файла журнала последних дней.
Что люди предлагают для максимального размера файла для различных методов / памяти, необходимых для хранения X строк, и каков наилучший метод для получения как можно большего количества файла журнала?
Например, какой-то способ зацикливания строки за строкой, пока не будет выполнено исключение, и затем сохранение того, что у меня есть.
Это мой метод GetHundredThousandLines, и он регистрирует в очень маленький файл отладки, чтобы я мог видеть, какие ошибки произошли во время процесса архивирования.
private bool GetHundredThousandLines(string logpath, string archivepath)
{
bool success = false;
int numberOfLines = 100000;
if (!File.Exists(logpath))
{
this.LogDebug("GetHundredThousandLines - Cannot find path " + logpath + " to archive " + numberOfLines.ToString() + " lines");
return false;
}
var queue = new Queue<string>(numberOfLines);
using (FileStream fs = File.Open(logpath, FileMode.Open, FileAccess.Read, FileShare.Read))
using (BufferedStream bs = new BufferedStream(fs)) // May not make much difference.
using (StreamReader sr = new StreamReader(bs))
{
while (!sr.EndOfStream)
{
if (queue.Count == numberOfLines)
{
queue.Dequeue();
}
queue.Enqueue(sr.ReadLine() + "\r\n");
}
}
// The queue now has our set of lines. So print to console, save to another file, etc.
try
{
do
{
File.AppendAllText(archivepath, queue.Dequeue(), Encoding.UTF8);
} while (queue.Count > 0);
}
catch (IOException exception)
{
this.LogDebug("GetHundredThousandLines - I/O Error accessing daily log file with ReadFileString: " + exception.Message.ToString());
}
catch (System.OutOfMemoryException exception)
{
this.LogDebug("GetHundredThousandLines - Out of Memory Error accessing daily log file with ReadFileString: " + exception.Message.ToString());
}
catch (Exception exception)
{
this.LogDebug("GetHundredThousandLines - Exception accessing daily log file with ReadFileString: " + exception.Message.ToString());
}
if (File.Exists(archivepath))
{
this.LogDebug("GetHundredThousandLines - Log file exists at " + archivepath);
success = true;
}
else
{
this.LogDebug("GetHundredThousandLines - Log file DOES NOT exist at " + archivepath);
}
return success;
}
Любая помощь приветствуется.
Спасибо
1 ответ
try: сохранить позицию очереди и потока в области видимости, попробуйте GC.Collect() при выходе из памяти исключение и снова вызвать функцию. искать поток до последней позиции и продолжить. или: используйте одну базу данных, такую как sqlite, и сохраняйте новейшие 100000 записей в каждой таблице.