Оптимизировать файл С# IO
Сценарий - текстовый файл в 150 Мбайт, который является экспортированной папкой "Входящие" старой учетной записи электронной почты. Вам нужно разобрать и вытащить электронные письма от конкретного пользователя и записать их в новый отдельный файл. У меня есть код, который работает, его просто преследуют медленно.
Я использую строки маркеров для поиска, где начинать/заканчивать копию из исходного файла.
Здесь основная функция:
StreamReader sr = new StreamReader("c:\\Thunderbird_Inbox.txt");
string working = string.Empty;
string mystring = string.Empty;
while (!sr.EndOfStream)
{
while ((mystring = sr.ReadLine()) != null)
{
if (mystring == strBeginMarker)
{
writeLog(mystring);
//read the next line
working = sr.ReadLine();
while( !(working.StartsWith(strEndMarker)))
{
writeLog(working);
working = sr.ReadLine();
}
}
}
}
this.Text = "DONE!!";
sr.Close();
Функция, которая записывает выбранные сообщения в новый файл:
public void writeLog(string sMessage)
{
fw = new System.IO.StreamWriter(path, true);
fw.WriteLine(sMessage);
fw.Flush();
fw.Close();
}
Опять же, этот процесс работает. Я получаю хороший выходной файл, это занимает много времени, и я уверен, что есть способы сделать это быстрее.
Ответы
Ответ 1
Самая большая оптимизация будет заключаться в том, чтобы изменить метод writeLog, чтобы открыть файл один раз в начале этой операции, написать ему много раз, а затем закрыть его в конце.
Прямо сейчас вы открываете и закрываете файл на каждой итерации, где вы пишете, что будет определенно замедлять работу.
Попробуйте следующее:
// Open this once at the beginning!
using(fw = new System.IO.StreamWriter(path, true))
{
using(StreamReader sr = new StreamReader("c:\\Thunderbird_Inbox.txt"))
{
string working;
string mystring;
while ((mystring = sr.ReadLine()) != null)
{
if (mystring == strBeginMarker)
{
writeLog(mystring);
//read the next line
working = sr.ReadLine();
while( !(working.StartsWith(strEndMarker)))
{
fw.WriteLine(working);
working = sr.ReadLine();
}
}
}
}
}
this.Text = "DONE!!";
Ответ 2
Думаю, вам следует:
- Откройте файлы один раз.
- Загрузите исходный файл в память.
- Разделите его и используйте несколько потоков для обработки.
Ответ 3
Я бы просто сделал простой парсер. Обратите внимание, что это предполагает (как и в вашем коде выше), что маркеры действительно уникальны.
Возможно, вам придется сыграть с форматированием немного вашего вывода, но вот общая идея:
// Read the entire file and close it
using (StreamReader sr = new
StreamReader("c:\\Thunderbird_Inbox.txt");)
{
string data = sr.ReadToEnd();
}
string newData = "";
int position = data.IndexOf(strBeginMarker);
while (position > 0)
{
int endPosition = data.IndexOf(endMarker, position);
int markerLength = position + strBeginMarker.Length;
newData += data.Substring(markerLength, endPosition - markerLength);
position = data.IndexOf(strBeginMarker, position+ endStr.Length);
}
writeLog(newData);
(Обратите внимание, что у меня нет файла размером 150 МБ для проверки этого на - YMMV в зависимости от используемого вами устройства).
Ответ 4
У меня нет текстового файла на 150 МБ для тестирования, но если на вашем сервере будет память, то будет считывать объект удержания в строку и делать регрессию, выводя сообщение из сообщения?
Ответ 5
Вы можете просто объявить объект StreamWriter за пределами этого цикла while
и просто записать строку внутри цикла.
Вот так:
StreamWriter sw = new StreamWriter(path, true);
while
{
// ...
while( !(working.StartsWith(strEndMarker)))
{
sw.WriteLine(working);
working = sr.ReadLine();
}
}