C#:逐行获取外部Shell命令的结果

5
我正在编写一个C#的winform应用程序,它启动第二个进程来执行shell命令,例如“dir”和“ping”。我重定向第二个进程的输出,这样我的应用程序就可以接收命令结果。它基本上运行得很好。
唯一的问题是我的winform应用程序会整体接收命令行输出,而不是逐行接收。例如,它必须等待外部“ping”命令完成(需要很长时间或更长时间),然后一次性接收整个输出内容(多行)。
我想要的是应用程序实时按行接收cmdline输出,而不是按块接收。这可行吗?
我正在使用以下代码读取输出: while ((result = proc.StandardOutput.ReadLine()) != null)
但它并没有按照我的预期工作。 谢谢。
编辑:这是我正在使用的代码:
    System.Diagnostics.ProcessStartInfo procStartInfo = new 
            System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);

    procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;

    // The following commands are needed to redirect the standard output.
    procStartInfo.RedirectStandardOutput = true;
    procStartInfo.UseShellExecute = false;
    procStartInfo.CreateNoWindow = true;
    // Now we create a process, assign its ProcessStartInfo and start it
    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    proc.StartInfo = procStartInfo;
    proc.Start();

    // Get the output into a string
    string result;
    try {
        while ((result = proc.StandardOutput.ReadLine()) != null)
        {
            AppendRtfText(result+"\n", Brushes.Black);
        }
    } // here I expect it to update the text box line by line in real time
      // but it does not.

1
可能重复:将控制台输出重定向到单独程序中的文本框 - Paolo Falabella
展示你尝试过的代码会很有帮助。 - Jalal Said
4个回答

3

请查看this msdn article中的示例,了解如何完全异步地进行读取。

除此之外,我期望你的代码现在按行读取,但UI没有时间重绘(在更新RTFTextBox后缺少Application.DoEvents();)


谢谢@Eddy,你是对的。但是在WPF中没有DoEvents()可用。我使用了这个解决方案:https://dev59.com/yG855IYBdhLWcg3wKw5Y - Charlie

2

不要使用循环while ((result = proc.StandardOutput.ReadLine()) != null),而应该使用:

...
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginOutputReadLine();
proc.WaitForExit();

当行到达时,这将启动异步读取行,然后您在proc_DataReceived处理程序中处理已读取的行,因为您使用了BeginOutputReadline,所以e.Data将是一个字符串行。



0

我曾经遇到过同样的问题,并通过以下方法解决。我发现,如果外部应用程序出现错误,使用ReadToEnd()方法将不会输出任何内容,因此改用逐行读取的streamreader。不过,我将转而使用Saa'd提供的答案,因为那似乎是处理它的正确方式。

我还发现了这个解决方案:c#编码规范public/private contexts,它同时提供了错误处理并对externalApp.OutputDataReceived += (sender, args) => Console.WriteLine(args.Data);的使用进行了更全面的解释。

Process externalApp = new Process();
        externalApp.StartInfo.FileName = config.ExternalApps + @"\location\DeleteApp.exe";
        externalApp.StartInfo.Arguments = Directory.GetCurrentDirectory() + @"\..\..\..\project\argumentsForDeleteApp.xml";
        externalApp.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
        externalApp.StartInfo.UseShellExecute = false;
        externalApp.StartInfo.RedirectStandardOutput = true;
        Console.Out.WriteLine(DateTime.UtcNow.ToLocalTime().ToString() +
            ":######    External app: " + externalApp.StartInfo.FileName + " -      START");
        externalApp.Start();
        using (StreamReader reader = externalApp.StandardOutput)
        {
            while (!reader.EndOfStream)
            {
                string result = reader.ReadLine();
                Console.Out.WriteLine(result);
            }
        }
        externalApp.WaitForExit();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接