Reputation: 61
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
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
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
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