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

发布于 2024-11-30 13:28:17 字数 1316 浏览 1 评论 0原文

我正在编写一个 C# winform 应用程序,它启动第二个进程来执行“dir”和“ping”等 shell 命令。我重定向第二个进程的输出,以便我的应用程序可以接收命令结果。大致工作得很好。

唯一的问题是我的 winform 应用程序接收整个命令行输出,而不是逐行接收。例如,它必须等待外部“ping”命令完成(这需要很多秒或更长时间),然后立即接收整个输出(很多行)。

我想要的是应用程序实时接收命令行输出,即按行而不是按块。这可行吗?

我正在使用此代码来读取输出: 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.

I am writing a C# winform application that starts a second process to execute shell commands like "dir" and "ping". I redirect the second process's output so my app can receive the command result. It roughly works fine.

The only problem is my winform app receives the command line output as a whole instead of line by line. For example, it has to wait for the external "ping" command to finish (which takes many seconds or longer) and then receives the whole output (many lines) at once.

What I want is the app receives the cmdline output in real-time, i.e. by lines not by block. Is this doable?

I am using this code to read the output:
while ((result = proc.StandardOutput.ReadLine()) != null)

But it does not work the way I expected.
Thanks in advance.

EDIT: here is the code I am using:

    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.

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

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

发布评论

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

评论(4

北城孤痞 2024-12-07 13:28:17

查看这篇 msdn 文章 关于如何完全异步进行读取。

除此之外,我希望您的代码现在可以逐行读取,但 UI 没有任何时间重新绘制(缺少 Application.DoEvents(); 更新 RTFTextBox 后

Have a look at the example in this msdn article on how to do the reading completly async.

Beyond that I expect your code does to read line by line now but the UI doesn't get any time to repaint (missing Application.DoEvents(); after updating the RTFTextBox

沙与沫 2024-12-07 13:28:17

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

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

这将在行到达时开始异步读取行,然后处理读取的行通过 proc_DataReceived 处理程序中的 e.Data,因为您使用 BeginOutputReadline,所以 e.Data 将是字符串lines 。

Instead of loop using while ((result = proc.StandardOutput.ReadLine()) != null) you should of using:

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

This will start asynchronous reading the lines when they arrives, you then handle the lines read by e.Data in proc_DataReceived handler, since you are use BeginOutputReadline the e.Data will be a string lines.

(り薆情海 2024-12-07 13:28:17

我遇到了同样的问题并通过以下方法解决了它。我发现,如果外部应用程序出现错误,我使用 ReadToEnd() 方法根本得不到任何输出,因此改用逐行流读取器。将切换到使用 Saa'd 提供的答案,因为这看起来是处理它的正确方法。

还找到了这个解决方案: c# 编码约定公共/私有上下文 它提供了同时进行错误处理并对 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();

I had the same issue and got around it with the following. I found that if I had an error in the external app I was getting no output at all using the ReadToEnd() method, so switched to use the line by line streamreader. Will be switching over to use the answer provided by Saa'd though as that looks like the proper way to handle it.

Also found this solution: c# coding convention public/private contexts which provides for error handling at the same time and giving a fuller explanation to the use of 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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文