Почему я пропускаю выходные данные при перенаправлении из процесса?

#c# #process

#c# #процесс

Вопрос:

Я вызываю консольное приложение, используя класс Process. Я перенаправляю вывод в файл журнала, но в окне консоли, когда я не перенаправляю вывод, появляется больше сообщений, чем в файле журнала, когда я перенаправляю. есть идеи, почему?

 ProcessStartInfo psi = new ProcessStartInfo();
string filename = @"ProgrammingMaster_LocalPowertrain.exe";
psi.FileName = filename;
string arguments = String.Format("{0} {1} false", InstanceId.ToString(), ManifestFolderPath);
psi.Arguments = arguments;
LogMessage(msgType.Warning, filename   " - "   arguments);
psi.UseShellExecute = false;
psi.CreateNoWindow = true;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
FBlockProcess = new Process();
FBlockProcess.StartInfo = psi;
FBlockProcess.OutputDataReceived  = new DataReceivedEventHandler(FBlockProcess_OutputDataReceived);
FBlockProcess.ErrorDataReceived  = new DataReceivedEventHandler(FBlockProcess_ErrorDataReceived);
FBlockProcess.Start();
FBlockProcess.BeginOutputReadLine();
FBlockProcess.BeginErrorReadLine();
  

в моем обработчике OutputDataReceived я просто добавляю строку в ConcurrentQueue

Редактировать: Я должен добавить, что я хочу записывать выходные данные в режиме реального времени или близко к нему. Запуск процесса может занять более 30 минут, я не хочу так долго ждать, чтобы увидеть, что происходит.

Обновление: После вывода первых четырех строк обработчик событий OutputDataReceived никогда не вызывается, хотя я знаю, что есть еще 10 или 15 строк, выводимых на консоль, когда я не перенаправляю. Есть идеи о том, что могло вызвать это?

Комментарии:

1. Возможно, это связано со сбросом потоков?

2. Вызываете ли вы WaitForExit() перед закрытием потоков?

3. @codymanix — нет. Я думал, что использование событий сделает это ненужным.

4. Объект process может быть собран мусором, и в этом случае вы больше не получите четности, попробуйте просто сохранить ссылку на него в статической переменной и посмотреть, исправит ли это проблему, не то, чтобы это было решением, но это легко проверить, чтобы увидеть, является ли GC виновником здесь.

5. @Lasse — Это необходимо, даже если я вижу, что процесс все еще запущен в диспетчере задач?

Ответ №1:

попробуйте этот пример:

 public static void Main()
{
    Process p = new Process();
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.Arguments = "/c dir *.cs";
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.RedirectStandardOutput = true;
    p.Start();

    string output = p.StandardOutput.ReadToEnd();

    Console.WriteLine("Output:");
    Console.WriteLine(output);    
}
  

Обновить

Я думаю, вы можете попробовать что-то полезное здесь:

http://msdn.microsoft.com/en-us/library/system.diagnostics.process.errordatareceived.aspx

Обновить

Я нашел эту ссылку, и «Решение 1» звучит как правильный путь:

http://www.codeproject.com/Answers/152467/Problem-executing-a-command-line-command-from-Csha.aspx?cmt=49313#answer1

Комментарии:

1. Таким образом, я не получу никаких выходных данных, пока они не закроются правильно?

2. Это выглядит так же, как я это делаю. вы видите, что я чего-то не понимаю?

3. проблема в том, что он компилирует все это как 1 строку, поэтому, если вы хотите просто прочитать одну строку, вы не можете…

Ответ №2:

Я столкнулся с аналогичной проблемой при попытке взаимодействия с приложением, которое требовало аутентификации. Peek () вернул бы -1 при обнаружении необычных символов (символы Юникода?) и ReadLine () также была ненадежной и в конечном итоге заблокировала бы мое приложение, поскольку, похоже, стандартный поток процесса не был закрыт.

Использование метода Read () было единственным способом гарантировать, что я получил ВСЕ строки и символы. Кроме того, использование обработчиков событий ErrorDataReceived процесса или OutputDataReceived также оказалось НЕНАДЕЖНЫМ (пропущенные строки). Ниже показано, как я решил свою проблему и обеспечил получение всех строк и символов:

 process.Start();
var stdOutput = process.StandardOutput;
StringBuilder fullMessage = new StringBuilder();
while (true)
{
    var character = (char)stdOutput.Read();
    fullMessage.Append(character);

    //Print Out All Characters
    Console.Write(character);
    if (fullMessage.ToString().EndsWith("Enter Password: "))
    {
        //Submit Password To Application
        using(StreamWriter writer = process.StandardInput){
            writer.Write("somepassword");
            writer.Flush();
        }

        break;
    }
}