user2026
user2026

Reputation: 61

Reading cmd output real time

I'm writing a program that reads python script output and shows the results in textbox. Since the script runnning for a long time, I want to be able to see the output every 1 second (or after each line is writen). Now i can see the output only when the process ends. Does someone know what is the problem?

snippet of my code:

Process p = new Process();
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.OutputDataReceived += new DataReceivedEventHandler (p_OutputDataReceived);
p.ErrorDataReceived += new DataReceivedEventHandler (p_ErrorDataReceived);
p.Exited += new EventHandler (p_Exited);
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.UseShellExecute = false;
p.StartInfo.FileName = "python.exe";
p.StartInfo.Arguments = "path " + commandline; 
p.Start(); 
StreamReader s = p.StandardOutput;
String output = s.ReadToEnd();
textBox3.Text = output;
p.WaitForExit();

Upvotes: 1

Views: 1792

Answers (3)

Aslam
Aslam

Reputation: 61

Python, by default, buffers its output. The way to go is to pass a "-u" command line argument to python.

so if you want to execute say hello.py, you would do :

python.exe -u hello.py

Heres the C# code that works for me.

Process p = new Process();
string op = "";
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = "c:\\python27\\python.exe";
StreamReader outputStream = p.StandardOutput;
StreamReader errorStream = p.StandardError;
p.StartInfo.Arguments = @"-u hello.py";
p.Start();
string output = "";
int offset = 0, readBytes = 0;
char[] buffer = new char[512];
do
{
    output = outputStream.ReadLine();
    if (!string.IsNullOrEmpty(output))
    {
        txtOutput.AppendText(output);
        txtOutput.AppendText(Environment.NewLine);
        offset += readBytes;
        Application.DoEvents();
    }
    Thread.Sleep(3);
} while (!p.HasExited);

Upvotes: 1

Magic Mick
Magic Mick

Reputation: 1523

I had this same problem running my Python script from C#. The problem is that Python buffers the output from stdout (print()).

You could do one of two things here.

1. Add the following to your Python script, after every print() line to flush the output.

import sys
print('Hello World!')
sys.stdout.flush()

2. Run the Python compiler with the -u command line parameter. This way you don't need to add the above flush line after every print.

...
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "python.exe -u path " + commandline; 
...

Upvotes: 2

Uwe Keim
Uwe Keim

Reputation: 40736

I'm doing it the following way in my own programs:

private static void startProgram(
    string commandLine )
{
    var fileName = commandLine;
    var arguments = string.Empty;
    checkSplitFileName( ref fileName, ref arguments );

    var info = new ProcessStartInfo();
    info.FileName = fileName;
    info.Arguments = arguments;

    info.UseShellExecute = false;
    info.RedirectStandardOutput = true;
    info.RedirectStandardError = true;

    using ( var p = new Process() )
    {
        p.StartInfo = info;
        p.EnableRaisingEvents = true;

        p.OutputDataReceived += (s,o) => { 
            Console.WriteLine(o.Data);
        };
        p.Start();

        p.BeginOutputReadLine();

        p.WaitForExit();
    }
}

I.e. I'm subscribing to the OutputDataReceived event and calling BeginOutputReadLine method. See also this similar Stack Overflow question.

(The method checkSplitFileName in my above source code can be found here)

Upvotes: 4

Related Questions