C # System.Diagnostics.Process перенаправление Standard Out для больших объемов данных - PullRequest
2 голосов
/ 26 мая 2010

Я запускаю exe из приложения .NET и пытаюсь перенаправить стандарт на потоковый ридер. Проблема в том, что когда я делаю

myprocess.exe >> out.txt

out.txt близко к 14 МБ. Когда я делаю версию для командной строки, это очень быстро, но когда я запускаю процесс из моего приложения csharp, это мучительно медленно, потому что я считаю, что по умолчанию потоковый читатель сбрасывает каждые 4096 байт.

Есть ли способ изменить средство чтения потоков по умолчанию для объекта Process?

Ответы [ 4 ]

5 голосов
/ 26 мая 2010

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

Process process = Process
    .Start(new ProcessStartInfo("a.exe"){RedirectStandardOutput = true});
if (process != null)
{
    process.OutputDataReceived += ((sender, e) =>
                                   {
                                       string consoleLine = e.Data;
                                       //handle data
                                   });
    process.BeginOutputReadLine();
}
4 голосов
/ 29 октября 2011

Редактировать: Просто понял, что я отвечаю не на тот вопрос. В моем случае буфер stdout был заполнен, а WaitForExit () блокировался навсегда, потому что из буфера еще ничего не читалось. Так что, если у вас есть проблема, вот решение. ;)

Это мой первый день с C #, поэтому, пожалуйста, поймите, что это может быть не лучшим решением и может не всегда работать. Но это работает в 2 раза, я проверял это. ;) Это синхронно, просто начните записывать перенаправленный stdout / stderr в файл до того, как подождите WaitForExit (). Таким образом, WaitForExit () не будет блокировать ожидание очистки буфера stdout.

      string str_MyProg = "my.exe";
      string str_CommandArgs = " arg1 arg2"'
      System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo(str_MyProg, str_CommandArgs);

      procStartInfo.RedirectStandardError = true;
      procStartInfo.RedirectStandardOutput = true; // Set true to redirect the process stdout to the Process.StandardOutput StreamReader
      procStartInfo.UseShellExecute = false;
      procStartInfo.CreateNoWindow = true;          // Do not create the black window

      // Create a process, assign its ProcessStartInfo and start it
      System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
      myProcess.StartInfo = procStartInfo;
      myProcess.Start();

      // Dump the output to the log file
      string stdOut = myProcess.StandardOutput.ReadToEnd();
      StreamWriter logFile = new StreamWriter("output.txt" );
      logFile.Write(stdOut);
      logFile.Close();

      myProcess.WaitForExit();          
3 голосов
/ 26 мая 2010

Да, это правильно. - это буфер, в котором хранятся выходные данные процесса, обычно от 1 до 4 КБ в распространенных реализациях CRT. Одна небольшая деталь: этот буфер находится в процессе, который вы запускаете, а не в программе .NET.

Ничего особенного не должно произойти, когда вы перенаправляете файл, CRT записывает его напрямую. Но если вы перенаправляете в свою .NET-программу, то вывод из буфера идет в канал. Который затем переводит поток в вашу программу, чтобы вы могли очистить канал. Вперед хорошо 700 раз.

Да, не быстро. Хотя это легко исправить, вызовите setvbuf () в программе, которую вы запускаете, чтобы увеличить размеры выходного буфера stdout и stderr. Опять же, это требует наличия исходного кода этой программы.

Предвидя проблему с этим: возможно, вам следует использовать cmd.exe / c для перенаправления в файл, а затем прочитать файл.

1 голос
/ 26 мая 2010

Класс Process напрямую предоставляет поток stdout, поэтому вы должны иметь возможность читать его в любом темпе, который вам нравится. Вероятно, лучше читать его небольшими порциями и избегать вызова ReadToEnd.

Например:

using(StreamReader sr = new StreamReader(myProcess.StandardOutput))
{
  string line;
  while((line = sr.ReadLine()) != null)
  {
    // do something with line
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...