Capturing binary output from Process.StandardOutput
Using StandardOutput.BaseStream
is the correct approach, but you must not use any other property or method of cmdProcess.StandardOutput
. For example, accessing cmdProcess.StandardOutput.EndOfStream
will cause the StreamReader
for StandardOutput
to read part of the stream, removing the data you want to access.
Instead, simply read and parse the data from br
(assuming you know how to parse the data, and won't read past the end of stream, or are willing to catch an EndOfStreamException
). Alternatively, if you don't know how big the data is, use Stream.CopyTo
to copy the entire standard output stream to a new file or memory stream.
Redirect binary data from Process.StandardOutput causes corrputed data
I found the problem. The redirection of the output was correct, the reading of the input seems to be the problem. So I changed the code from:
using (var streamReader = new StreamReader(configuration.Source))
{
process.StandardInput.Write(streamReader.ReadToEnd());
process.StandardInput.Flush();
process.StandardInput.Close();
}
to
using (var fileStream = new StreamReader(configuration.Source))
{
fileStream.BaseStream.CopyTo(process.StandardInput.BaseStream);
process.StandardInput.Close();
}
Not it works!
For all the people that might have the same problem, here the corrected code:
var process = new Process
{
StartInfo =
{
Arguments = string.Format(@"-display"),
FileName = configuration.PathToExternalSift,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
},
EnableRaisingEvents = true
};
process.ErrorDataReceived += (ProcessErrorDataReceived);
process.Start();
process.BeginErrorReadLine();
//read in the file.
using (var fileStream = new StreamReader(configuration.Source))
{
fileStream.BaseStream.CopyTo(process.StandardInput.BaseStream);
process.StandardInput.Close();
}
//redirect output to file.
using (var fileStream = new FileStream(configuration.Destination, FileMode.OpenOrCreate))
{
process.StandardOutput.BaseStream.CopyTo(fileStream);
}
process.WaitForExit();
Getting Binary Data from StandardOutput
Bradley Grainger who made a comment on the question was right. The event handlers don't support retrieving binary data from standard out. Had to switch over to using a main loop and pulling data from standard out using the read functions.
Connect Process StandardOutput to another Process StandardInput
Apparently, CopyToAsync
doesn't close the output stream on completion. This didn't matter for my MemoryStream, but obviously I need to close a process's StandardInput or it won't ever complete.
I made this method:
private static async Task CopyThenClose(Stream from, Stream to)
{
await from.CopyToAsync(to);
to.Close();
}
And replaced the calls to CopyToAsync
; eg.:
tasks.Add(CopyThenClose(process1.StandardOutput.BaseStream, process2.StandardInput.BaseStream));
Redirecting Standard Output in .NET with a BinaryReader - detecting EOS / forcing a time out
The Process.Exited
event will only be raised if you've set Process.EnableRaisingEvents
to true
. If you do that, you should be getting process exit notifications via Process.Exited
or via the synchronous Process.WaitForExit
method.
If you're still not getting this event, see if your child process is terminating gracefully (though even then I would still expect Exited
to fire).
Load standart output and parse it to Image
From the comments it seems the program is expecting the StandardInput
to be finished before returning the content. Close the StandardInput
to achieve it:
p.StandardInput.WriteLine(input);
p.StandardInput.BaseStream.Close();
Capture standard output and still display it in the console window
Once you've redirected standard out it's no longer directed at the console. To write to the console you'll have to do it manually.
If you want to display output as the process executes, instead of in 1 big dump at the end, you can use the "OutputDataReceived" event of the Process class.
Related Topics
How to Convert an Iso8601 Timespan to a C# Timespan
Passing Object in Redirecttoaction
Non-Static Method Requires a Target
How to Access Configuration in Any Class in ASP.NET Core
Exclude Property on Update in Entity Framework
Webapi Streamcontent VS Pushstreamcontent
How to Detect If Type Is Another Generic Type
Make ASP.NET Wcf Convert Dictionary to JSON, Omitting "Key" & "Value" Tags
SQL Where Clause Matching Values with Trailing Spaces
Why Can't I Assign a List<Derived> to a List<Base>
Date of Birth Validation Keeps Showing
Why Are C# Interface Methods Not Declared Abstract or Virtual
How to Use the C#6 "Using Static" Feature
How to Check All Properties of an Object Whether Null or Empty