StandardOutput.ReadToEnd() 挂起

发布于 2024-11-30 20:32:20 字数 1669 浏览 1 评论 0原文

我有一个经常使用外部程序并读取其输出的程序。 使用通常的进程重定向输出它工作得很好,但是当我尝试读取它时,一个特定的参数由于某种原因挂起,没有错误消息 - 没有例外,它只是在到达该行时“停止”。 我当然使用集中函数来调用和读取程序的输出,即:

public string ADBShell(string adbInput)
{
    try
    {
        //Create Empty values
        string result = string.Empty;
        string error = string.Empty;
        string output = string.Empty;
        System.Diagnostics.ProcessStartInfo procStartInfo 
            = new System.Diagnostics.ProcessStartInfo(toolPath + "adb.exe");

        procStartInfo.Arguments = adbInput;
        procStartInfo.RedirectStandardOutput = true;
        procStartInfo.RedirectStandardError = true;
        procStartInfo.UseShellExecute = false;
        procStartInfo.CreateNoWindow = true;
        procStartInfo.WorkingDirectory = toolPath;
        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.StartInfo = procStartInfo;
        proc.Start();
        // Get the output into a string
        proc.WaitForExit();
        result = proc.StandardOutput.ReadToEnd();
        error = proc.StandardError.ReadToEnd();  //Some ADB outputs use this
        if (result.Length > 1)
        {
            output += result;
        }
        if (error.Length > 1)
        {
            output += error;
        }
        Return output;
    }
    catch (Exception objException)
    {
        throw objException;
    }
}

挂起的行是 result = proc.StandardOutput.ReadToEnd();,但同样,并非每次都是,仅当发送特定参数(“启动服务器”)时。所有其他参数都工作得很好 - 它读取值并返回它。 它悬挂的方式也很奇怪。它不会冻结或给出错误或任何其他内容,它只是停止处理。就像它是一个“返回”命令一样,除了它甚至不返回到调用函数之外,它只是停止一切,而界面仍然启动并运行。 以前有人经历过这个吗?有人知道我应该尝试什么吗?我假设这是流本身中意外的事情,但是有没有办法可以处理/忽略它,以便它无论如何都可以读取它?

I have a program that frequently uses an external program and reads its outputs.
It works pretty well using your usual process redirect output, but one specific argument for some reason hangs when I try to read it, no error message - no exception, it just 'stops' when it reaches that line.
I of course use a centralized function to call and read output from the program, which is this:

public string ADBShell(string adbInput)
{
    try
    {
        //Create Empty values
        string result = string.Empty;
        string error = string.Empty;
        string output = string.Empty;
        System.Diagnostics.ProcessStartInfo procStartInfo 
            = new System.Diagnostics.ProcessStartInfo(toolPath + "adb.exe");

        procStartInfo.Arguments = adbInput;
        procStartInfo.RedirectStandardOutput = true;
        procStartInfo.RedirectStandardError = true;
        procStartInfo.UseShellExecute = false;
        procStartInfo.CreateNoWindow = true;
        procStartInfo.WorkingDirectory = toolPath;
        System.Diagnostics.Process proc = new System.Diagnostics.Process();
        proc.StartInfo = procStartInfo;
        proc.Start();
        // Get the output into a string
        proc.WaitForExit();
        result = proc.StandardOutput.ReadToEnd();
        error = proc.StandardError.ReadToEnd();  //Some ADB outputs use this
        if (result.Length > 1)
        {
            output += result;
        }
        if (error.Length > 1)
        {
            output += error;
        }
        Return output;
    }
    catch (Exception objException)
    {
        throw objException;
    }
}

The line that hangs is result = proc.StandardOutput.ReadToEnd();, but again, not every time, only when sent a specific argument ("start-server"). All other arguments work just fine - it reads the value and returns it.
It's also strange the way it hangs. It doesn't freeze or give an error or anything, it just stops processing. As if it was a 'return' command, except it doesn't even return to the calling function, it just stops everything with the interface still up and running.
Anyone experienced this before? Anyone have any idea what I should try? I'm assuming it's something unexpected within the stream itself, but is there a way I can handle/ignore this so that it reads it anyway?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

时光清浅 2024-12-07 20:32:20

建议的使用 BeginOutputReadLine() 的解决方案是一个好方法,但在这种情况下,它不适用,因为进程(当然使用 WaitForExit())比异步退出更早输出完全完成。

因此,我尝试同步实现它,发现解决方案是使用 StreamReader 类中的 Peek() 方法。我添加了对 Peek() > 的检查-1 以确保它不是流的结尾,如 MSDN 文章 进行了描述,终于可以工作了,不再挂起!

这是代码:

var process = new Process();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = @"C:\test\";
process.StartInfo.FileName = "test.exe";
process.StartInfo.Arguments = "your arguments here";

process.Start();
var output = new List<string>();

while (process.StandardOutput.Peek() > -1)
{
    output.Add(process.StandardOutput.ReadLine());
}

while (process.StandardError.Peek() > -1)
{
    output.Add(process.StandardError.ReadLine());
}
process.WaitForExit();

Proposed solutions with BeginOutputReadLine() are a good way but in situations such as that, it is not applicable, because process (certainly with using WaitForExit()) exits earlier than async output finished completely.

So, I tried to implement it synchronously and found that the solution is in using Peek() method from StreamReader class. I added check for Peek() > -1 to sure that it is not the end of the stream as in MSDN article described and finally it works and stop hanging!

Here is the code:

var process = new Process();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.WorkingDirectory = @"C:\test\";
process.StartInfo.FileName = "test.exe";
process.StartInfo.Arguments = "your arguments here";

process.Start();
var output = new List<string>();

while (process.StandardOutput.Peek() > -1)
{
    output.Add(process.StandardOutput.ReadLine());
}

while (process.StandardError.Peek() > -1)
{
    output.Add(process.StandardError.ReadLine());
}
process.WaitForExit();
江湖彼岸 2024-12-07 20:32:20

问题是您在 StandardOutputStandardError 流上使用同步 ReadToEnd 方法。这可能会导致您遇到潜在的僵局。 MSDN 中甚至对此进行了描述。那里描述了解决方案。基本上,它是:使用异步版本 BeginOutputReadLine读取StandardOutput流的数据:

p.BeginOutputReadLine();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();

使用BeginOutputReadLine实现异步读取见ProcessStartInfo 挂在“WaitForExit”上?为什么?

The problem is that you are using the synchronous ReadToEnd methods on both the StandardOutput and the StandardError streams. This can lead to a potential deadlock you are experiencing. This is even described in the MSDN. The solution is described there. Basically, it is: Use the asynchronous version BeginOutputReadLine to read the data of the StandardOutput stream:

p.BeginOutputReadLine();
string error = p.StandardError.ReadToEnd();
p.WaitForExit();

Implementation of Async reading using BeginOutputReadLine see in ProcessStartInfo hanging on "WaitForExit"? Why?

夜空下最亮的亮点 2024-12-07 20:32:20

怎么样:

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();

process.OutputDataReceived += (sender, args) =>
{
    var outputData = args.Data;
    // ...
};
process.ErrorDataReceived += (sender, args) =>
{
    var errorData = args.Data;
    // ...
};
process.WaitForExit();

What about something like:

process.Start();
process.BeginOutputReadLine();
process.BeginErrorReadLine();

process.OutputDataReceived += (sender, args) =>
{
    var outputData = args.Data;
    // ...
};
process.ErrorDataReceived += (sender, args) =>
{
    var errorData = args.Data;
    // ...
};
process.WaitForExit();
转瞬即逝 2024-12-07 20:32:20

我有同样的死锁问题。这个代码片段对我有用。

ProcessStartInfo startInfo = new ProcessStartInfo("cmd")
{
    WindowStyle = ProcessWindowStyle.Hidden,
    UseShellExecute = false,
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    CreateNoWindow = true
};

Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("echo hi");
process.StandardInput.WriteLine("exit");
var output = process.StandardOutput.ReadToEnd();
process.Dispose();

I had the same deadlock problem. This code snippet worked for me.

ProcessStartInfo startInfo = new ProcessStartInfo("cmd")
{
    WindowStyle = ProcessWindowStyle.Hidden,
    UseShellExecute = false,
    RedirectStandardInput = true,
    RedirectStandardOutput = true,
    CreateNoWindow = true
};

Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.StandardInput.WriteLine("echo hi");
process.StandardInput.WriteLine("exit");
var output = process.StandardOutput.ReadToEnd();
process.Dispose();
┾廆蒐ゝ 2024-12-07 20:32:20

我遇到了同样的问题,错误只是挂起。

根据您对 Daniel Hilgarth 的回复,我什至没有尝试使用这些代码,尽管我认为它们对我有用。

由于我希望能够做出一些更精美的输出,最终我决定在后台线程中完成两个输出。

public static class RunCommands
{
    #region Outputs Property

    private static object _outputsLockObject;
    private static object OutputsLockObject
    { 
        get
        {
            if (_outputsLockObject == null)
                Interlocked.CompareExchange(ref _outputsLockObject, new object(), null);
            return _outputsLockObject;
        }
    }

    private static Dictionary<object, CommandOutput> _outputs;
    private static Dictionary<object, CommandOutput> Outputs
    {
        get
        {
            if (_outputs != null)
                return _outputs;

            lock (OutputsLockObject)
            {
                _outputs = new Dictionary<object, CommandOutput>();
            }
            return _outputs;
        }
    }

    #endregion

    public static string GetCommandOutputSimple(ProcessStartInfo info, bool returnErrorIfPopulated = true)
    {
        // Redirect the output stream of the child process.
        info.UseShellExecute = false;
        info.CreateNoWindow = true;
        info.RedirectStandardOutput = true;
        info.RedirectStandardError = true;
        var process = new Process();
        process.StartInfo = info;
        process.ErrorDataReceived += ErrorDataHandler;
        process.OutputDataReceived += OutputDataHandler;

        var output = new CommandOutput();
        Outputs.Add(process, output);

        process.Start();

        process.BeginErrorReadLine();
        process.BeginOutputReadLine();

        // Wait for the process to finish reading from error and output before it is finished
        process.WaitForExit();

        process.ErrorDataReceived -= ErrorDataHandler;
        process.OutputDataReceived -= OutputDataHandler;

        Outputs.Remove(process);

        if (returnErrorIfPopulated && (!String.IsNullOrWhiteSpace(output.Error)))
        {
            return output.Error.TrimEnd('\n');
        }

        return output.Output.TrimEnd('\n');
    }

    private static void ErrorDataHandler(object sendingProcess, DataReceivedEventArgs errLine)
    {
        if (errLine.Data == null)
            return;

        if (!Outputs.ContainsKey(sendingProcess))
            return;

        var commandOutput = Outputs[sendingProcess];

        commandOutput.Error = commandOutput.Error + errLine.Data + "\n";
    }

    private static void OutputDataHandler(object sendingProcess, DataReceivedEventArgs outputLine)
    {
        if (outputLine.Data == null)
            return;

        if (!Outputs.ContainsKey(sendingProcess))
            return;

        var commandOutput = Outputs[sendingProcess];

        commandOutput.Output = commandOutput.Output + outputLine.Data + "\n";
    }
}
public class CommandOutput
{
    public string Error { get; set; }
    public string Output { get; set; }

    public CommandOutput()
    {
        Error = "";
        Output = "";
    }
}

这对我有用,让我不必在读取时使用超时。

I had the same kind of problem that error was just hanging.

Based on your response to Daniel Hilgarth I didn't even try using those codes though i think they would have worked for me.

Since I want to be able do some fancier output still eventually i decided that I would do it with both of the outputs being done in a background thread.

public static class RunCommands
{
    #region Outputs Property

    private static object _outputsLockObject;
    private static object OutputsLockObject
    { 
        get
        {
            if (_outputsLockObject == null)
                Interlocked.CompareExchange(ref _outputsLockObject, new object(), null);
            return _outputsLockObject;
        }
    }

    private static Dictionary<object, CommandOutput> _outputs;
    private static Dictionary<object, CommandOutput> Outputs
    {
        get
        {
            if (_outputs != null)
                return _outputs;

            lock (OutputsLockObject)
            {
                _outputs = new Dictionary<object, CommandOutput>();
            }
            return _outputs;
        }
    }

    #endregion

    public static string GetCommandOutputSimple(ProcessStartInfo info, bool returnErrorIfPopulated = true)
    {
        // Redirect the output stream of the child process.
        info.UseShellExecute = false;
        info.CreateNoWindow = true;
        info.RedirectStandardOutput = true;
        info.RedirectStandardError = true;
        var process = new Process();
        process.StartInfo = info;
        process.ErrorDataReceived += ErrorDataHandler;
        process.OutputDataReceived += OutputDataHandler;

        var output = new CommandOutput();
        Outputs.Add(process, output);

        process.Start();

        process.BeginErrorReadLine();
        process.BeginOutputReadLine();

        // Wait for the process to finish reading from error and output before it is finished
        process.WaitForExit();

        process.ErrorDataReceived -= ErrorDataHandler;
        process.OutputDataReceived -= OutputDataHandler;

        Outputs.Remove(process);

        if (returnErrorIfPopulated && (!String.IsNullOrWhiteSpace(output.Error)))
        {
            return output.Error.TrimEnd('\n');
        }

        return output.Output.TrimEnd('\n');
    }

    private static void ErrorDataHandler(object sendingProcess, DataReceivedEventArgs errLine)
    {
        if (errLine.Data == null)
            return;

        if (!Outputs.ContainsKey(sendingProcess))
            return;

        var commandOutput = Outputs[sendingProcess];

        commandOutput.Error = commandOutput.Error + errLine.Data + "\n";
    }

    private static void OutputDataHandler(object sendingProcess, DataReceivedEventArgs outputLine)
    {
        if (outputLine.Data == null)
            return;

        if (!Outputs.ContainsKey(sendingProcess))
            return;

        var commandOutput = Outputs[sendingProcess];

        commandOutput.Output = commandOutput.Output + outputLine.Data + "\n";
    }
}
public class CommandOutput
{
    public string Error { get; set; }
    public string Output { get; set; }

    public CommandOutput()
    {
        Error = "";
        Output = "";
    }
}

This worked for me and allowed me to not have to use a timeout for the read.

虫児飞 2024-12-07 20:32:20

对我来说优雅且有用的东西是:

Process nslookup = new Process()
{
   StartInfo = new ProcessStartInfo("nslookup")
   {
      RedirectStandardInput = true,
      RedirectStandardOutput = true,
      UseShellExecute = false,
      CreateNoWindow = true,
      WindowStyle = ProcessWindowStyle.Hidden
   }
};

nslookup.Start();
nslookup.StandardInput.WriteLine("set type=srv");
nslookup.StandardInput.WriteLine("_ldap._tcp.domain.local"); 

nslookup.StandardInput.Flush();
nslookup.StandardInput.Close();

string output = nslookup.StandardOutput.ReadToEnd();

nslookup.WaitForExit();
nslookup.Close();

我在此处找到了这个答案诀窍是在标准输入上使用 Flush()Close()

Something that is elegant and worked for me is:

Process nslookup = new Process()
{
   StartInfo = new ProcessStartInfo("nslookup")
   {
      RedirectStandardInput = true,
      RedirectStandardOutput = true,
      UseShellExecute = false,
      CreateNoWindow = true,
      WindowStyle = ProcessWindowStyle.Hidden
   }
};

nslookup.Start();
nslookup.StandardInput.WriteLine("set type=srv");
nslookup.StandardInput.WriteLine("_ldap._tcp.domain.local"); 

nslookup.StandardInput.Flush();
nslookup.StandardInput.Close();

string output = nslookup.StandardOutput.ReadToEnd();

nslookup.WaitForExit();
nslookup.Close();

This answer I found here and the trick is using Flush() and Close() on standard input.

救赎№ 2024-12-07 20:32:20

接受的答案的解决方案对我不起作用。我必须使用任务来避免死锁:

//Code to start process here

String outputResult = GetStreamOutput(process.StandardOutput);
String errorResult = GetStreamOutput(process.StandardError);

process.WaitForExit();

使用 GetStreamOutput 函数,如下所示:

private string GetStreamOutput(StreamReader stream)
{
   //Read output in separate task to avoid deadlocks
   var outputReadTask = Task.Run(() => stream.ReadToEnd());

   return outputReadTask.Result;
}

The accepted answer's solution didn't work for me. I had to use tasks in order to avoid the deadlock:

//Code to start process here

String outputResult = GetStreamOutput(process.StandardOutput);
String errorResult = GetStreamOutput(process.StandardError);

process.WaitForExit();

With a GetStreamOutput function as follows:

private string GetStreamOutput(StreamReader stream)
{
   //Read output in separate task to avoid deadlocks
   var outputReadTask = Task.Run(() => stream.ReadToEnd());

   return outputReadTask.Result;
}
攀登最高峰 2024-12-07 20:32:20

以防万一有人在想要使用 Windows 窗体和 TextBox(或 RichTextBox)来显示错误并输出过程实时返回的输出时偶然发现这个问题(因为它们是写入 process.StandardOutput / process.StandardError)。

您需要使用 OutputDataReceived() / ErrorDataReceived() 才能在没有死锁的情况下读取两个流,否则无法(据我所知)避免死锁,即使是费多尔的答案,现在拥有“答案”标签并且是最新的最受欢迎的答案,对我来说也不起作用。

然而,当您使用RichTextBox(或TextBox)输出数据时,您遇到的另一个问题是如何将数据实时(一旦到达)实际写入文本框。您可以在后台线程 OutputDataReceived() / ErrorDataReceived() 之一内接收对数据的访问权限,并且您只能从主线程。

我首先尝试做的是从后台线程调用 process.Start() ,然后调用 BeginInvoke() => OutputDataReceived() / ErrorDataReceived() 线程中的 AppendText(),而主线程是 process.WaitForExit()

然而,这导致我的身体冻结并最终永远悬吊着。经过几天的尝试,我最终得到了下面的解决方案,这似乎工作得很好。

简而言之,您需要将消息添加到 OutputDataReceived() / ErrorDataReceived() 线程内的并发集合中,而主线程应不断尝试从该集合中提取消息,并且将它们附加到文本框中:

            ProcessStartInfo startInfo
                = new ProcessStartInfo(File, mysqldumpCommand);

            process.StartInfo.FileName = File;
            process.StartInfo.Arguments = mysqldumpCommand;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.RedirectStandardInput = false;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
            process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            process.EnableRaisingEvents = true;

            ConcurrentQueue<string> messages = new ConcurrentQueue<string>();

            process.ErrorDataReceived += (object se, DataReceivedEventArgs ar) =>
            {
                string data = ar.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    messages.Enqueue(data);
            };
            process.OutputDataReceived += (object se, DataReceivedEventArgs ar) =>
            {
                string data = ar.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    messages.Enqueue(data);
            };

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();
            while (!process.HasExited)
            {
                string data = null;
                if (messages.TryDequeue(out data))
                    UpdateOutputText(data, tbOutput);
                Thread.Sleep(5);
            }

            process.WaitForExit();

这种方法的唯一缺点是,当进程开始在 process.Start()process 之间写入消息时,您可能会在极少数情况下丢失消息。 BeginErrorReadLine() / process.BeginOutputReadLine(),请记住这一点。避免这种情况的唯一方法是读取完整的流和(或)仅在进程完成时才能访问它们。

Just in case someone stumbles upon this question while wiling to use Windows Forms and TextBox (or RichTextBox) to show the errors and outputs the process returns in real time (as they are written to process.StandardOutput / process.StandardError).

You need to use OutputDataReceived() / ErrorDataReceived() in order to read both streams without deadlocks, there is no way (as far as I know) to avoid deadlocks otherwise, even Fedor's answer, which now holds the "Answer" tag and the most likes up to date, does not do the trick for me.

However, when you use the RichTextBox (or TextBox) to output the data, another problem you encounter is how to actually write the data into the textbox in real time (once it arrives). You receive the access to the data inside one of the background threads OutputDataReceived() / ErrorDataReceived() and you can only AppendText() from the main thread.

What I first tried doing was calling process.Start() from a background thread and then calling BeginInvoke() => AppendText() in OutputDataReceived() / ErrorDataReceived() threads while the main thread was process.WaitForExit().

However, this led to my form freezing and ultimately hanging for eternity. After a few days of trying I ended up with the solution below, that seems to work pretty well.

Shortly speaking, you need to add the messages into a concurrent collection inside OutputDataReceived() / ErrorDataReceived() threads while the main thread should constantly try to extract messages from that collection and append them into the textbox:

            ProcessStartInfo startInfo
                = new ProcessStartInfo(File, mysqldumpCommand);

            process.StartInfo.FileName = File;
            process.StartInfo.Arguments = mysqldumpCommand;
            process.StartInfo.CreateNoWindow = true;
            process.StartInfo.UseShellExecute = false;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
            process.StartInfo.RedirectStandardInput = false;
            process.StartInfo.RedirectStandardError = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
            process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
            process.EnableRaisingEvents = true;

            ConcurrentQueue<string> messages = new ConcurrentQueue<string>();

            process.ErrorDataReceived += (object se, DataReceivedEventArgs ar) =>
            {
                string data = ar.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    messages.Enqueue(data);
            };
            process.OutputDataReceived += (object se, DataReceivedEventArgs ar) =>
            {
                string data = ar.Data;
                if (!string.IsNullOrWhiteSpace(data))
                    messages.Enqueue(data);
            };

            process.Start();
            process.BeginErrorReadLine();
            process.BeginOutputReadLine();
            while (!process.HasExited)
            {
                string data = null;
                if (messages.TryDequeue(out data))
                    UpdateOutputText(data, tbOutput);
                Thread.Sleep(5);
            }

            process.WaitForExit();

The only downside of this approach is the fact that you can loose messages in a quite rare case, when process starts writing them between process.Start() and process.BeginErrorReadLine() / process.BeginOutputReadLine(), just keep that in mind. The only way to avoid that is to read the full streams and (or) gain access to them only when the process finishes.

奢欲 2024-12-07 20:32:20

第一

     // Start the child process.
     Process p = new Process();
     // Redirect the output stream of the child process.
     p.StartInfo.UseShellExecute = false;
     p.StartInfo.RedirectStandardOutput = true;
     p.StartInfo.FileName = "Write500Lines.exe";
     p.Start();
     // Do not wait for the child process to exit before
     // reading to the end of its redirected stream.
     // p.WaitForExit();
     // Read the output stream first and then wait.
     string output = p.StandardOutput.ReadToEnd();
     p.WaitForExit();

 // Do not perform a synchronous read to the end of both 
 // redirected streams.
 // string output = p.StandardOutput.ReadToEnd();
 // string error = p.StandardError.ReadToEnd();
 // p.WaitForExit();
 // Use asynchronous read operations on at least one of the streams.
 p.BeginOutputReadLine();
 string error = p.StandardError.ReadToEnd();
 p.WaitForExit();

这是来自 MSDN

first

     // Start the child process.
     Process p = new Process();
     // Redirect the output stream of the child process.
     p.StartInfo.UseShellExecute = false;
     p.StartInfo.RedirectStandardOutput = true;
     p.StartInfo.FileName = "Write500Lines.exe";
     p.Start();
     // Do not wait for the child process to exit before
     // reading to the end of its redirected stream.
     // p.WaitForExit();
     // Read the output stream first and then wait.
     string output = p.StandardOutput.ReadToEnd();
     p.WaitForExit();

second

 // Do not perform a synchronous read to the end of both 
 // redirected streams.
 // string output = p.StandardOutput.ReadToEnd();
 // string error = p.StandardError.ReadToEnd();
 // p.WaitForExit();
 // Use asynchronous read operations on at least one of the streams.
 p.BeginOutputReadLine();
 string error = p.StandardError.ReadToEnd();
 p.WaitForExit();

This is from MSDN

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文