简体   繁体   English

如何在没有死锁的情况下正确读取c#进程标准错误流?

[英]How to properly read c# process standard error stream without deadlocks?

It really feels like I'm following best practices according to MSDN . 根据MSDN,我真的觉得我在遵循最佳实践。 But I'm most likely missing something because my code hangs after continuing from this line: string errorOutput = cmd.StandardError.ReadToEnd(); 但是我很可能遗漏了一些东西,因为我的代码在从这一行继续后挂起: string errorOutput = cmd.StandardError.ReadToEnd(); . What am I doing wrong? 我究竟做错了什么?

        var batchfile = File.OpenWrite("run.bat");
        StreamWriter writer = new StreamWriter(batchfile);
        writer.Write("dotnet run" + '\n');
        //writer.Write("set /p temp=\"Hit enter to continue\"" + '\n');
        writer.Close();

        var cmd = new Process();
        cmd.StartInfo.FileName = batchfile.Name;
        cmd.StartInfo.UseShellExecute = false;
        cmd.StartInfo.RedirectStandardError = true;

        cmd.Start();
        string errorOutput = cmd.StandardError.ReadToEnd();
        cmd.WaitForExit();

        var outputfile = File.OpenWrite("run_errorOut.txt");
        StreamWriter outputWriter = new StreamWriter(outputfile);
        outputWriter.Write(errorOutput);
        outputWriter.Close();

In case it helps: At the moment this code is running inside an xunit test inside a dotnetcore2.2 app (its target framework is 'netcoreapp2.2'). 万一它有帮助:目前这个代码在dotnetcore2.2应用程序内部的xunit测试中运行(其目标框架是'netcoreapp2.2')。

So I had a very similar problem not that long ago, doing almost exactly the same and what I found was that: 所以我有一个非常类似的问题,不久前,几乎完全一样,我发现的是:

  • Trying to read StandardError/Output without there being anything to read blocks until there is something to read (or deadlock if nothing is ever written - eg process has exited) 尝试读取标准错误/输出而没有任何东西可以读取块,直到有东西要读(如果没有写任何东西就死锁 - 例如进程退出)
  • cmd.HasExited is false until the StandardError/Output has been read so that cannot be used to detect when finished (and then read StandardError/Output) cmd.HasExited为false,直到读取StandardError / Output,因此无法用于检测何时完成(然后读取StandardError / Output)

The most reliable way I have found to do this is to use the provided events on Process : 我发现这样做最可靠的方法是在Process上使用提供的事件:

var outData = new StringBuilder();
var errData = new StringBuilder();    

cmd.OutputDataReceived += (sender, args) => outData.Append(args.Data ?? string.Empty);
cmd.ErrorDataReceived += (sender, args) => errData.Append(args.Data ?? string.Empty);

And then after cmd.Start() == true : 然后在cmd.Start() == true

cmd.BeginErrorReadLine();
cmd.BeginOutputReadLine();

To start the events firing. 开始射击的事件。

After the process has exited you can call .ToString() on the StringBuilders to get the data: 进程退出后,您可以在StringBuilders上调用.ToString()来获取数据:

Console.WriteLine(outData.ToString());
Console.WriteLine(errData.ToString());

(Note that .ToString() can be implicit when using Console.WriteLine ) (注意,使用Console.WriteLine.ToString()可以是隐式的)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM