Оптимизировать файл ввода-вывода C # - PullRequest
13 голосов
/ 20 января 2011

Сценарий - текстовый файл размером 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();
    }

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

Ответы [ 5 ]

19 голосов
/ 20 января 2011

Самой большой оптимизацией было бы изменение метода 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 голосов
/ 20 января 2011

Я бы просто сделал простой парсер.Обратите внимание, что это предполагает (как вы делаете в своем коде выше), что маркеры на самом деле уникальны.

Возможно, вам придется немного поиграть с форматированием вашего вывода, но вот общая идея:*

   // 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 в зависимости от используемой машины).

2 голосов
/ 20 января 2011

Я думаю, вы должны:

  1. Открыть файлы один раз.
  2. Загрузить исходный файл в память.
  3. Разбейте его и используйте несколько потоков для обработки.
0 голосов
/ 20 января 2011

Вы можете просто объявить объект StreamWriter вне этого цикла while и просто записать в него строку внутри цикла.

Например:

StreamWriter sw = new StreamWriter(path, true);
while
{
    // ...
    while( !(working.StartsWith(strEndMarker)))
    {
        sw.WriteLine(working);
        working = sr.ReadLine();
    }
}
0 голосов
/ 20 января 2011

У меня нет текстового файла объемом 150 МБ для тестирования, но если на вашем сервере есть память, Считывание удерживающей вещи в строку и выполнение RegEx вытаскивает сообщение?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...