views:

406

answers:

3

I know that there're stdout/in/err for a program and I want to redirect a program's output to a file instead of the console output. And I now figure it out with the code below:

FileStream fs = File.Open(@"E:\console.txt", FileMode.OpenOrCreate);
StreamWriter sw = new StreamWriter(fs);
TextWriter old = Console.Out;
Console.SetOut(sw);
Console.Write("bbb");
sw.Flush();

But this approach is to connect the program's stdout to Console.Out and redirect the Console.Out to the file. It's kind of like this:

Program.StdOut -> Console.Out -> File

The Console.Out here seems to be a bridge. I don't want this bridge and I don't want to use Console.Write() to make the output. How could I map the program's stdout stream to the target file directly and write to the program's stdout directly instead of Console.Write()? What I want is kind of like this:

Program.StdOut -> File

The Process.StandardOutput property only gives me a readonly StreamReader object. How to write to the Process.StandardOutput?? Or where is the program's stdout?

Many thanks.

+1  A: 

use ProcessStartInfo and Process classes and set RedirectStandardOutput to true, then you can capture the output from a stream.

ProcessStartInfo info = new ProcessStartInfo("process.exe", "-arg1 -arg2");
info.RedirectStandardOutput = true;
Process p = Process.Start(info);
p.Start();
string output = p.StandardOutput.ReadToEnd();
Jake
Thanks,Jake. I want to know that in the process.exe, how to write to the program's standard output? What kind of code implement that? Is it still a Console.Write()? Is there a way not to use this method and write directly to the program's stdout?
smwikipedia
You need to tee the program's output to both StdOut and your 2nd stream. One way is to write a loop calling `ReadToEnd()`, write to both outputs, then sleep a bit, repeat until stream has been closed.
spoulson
Set `info.UseShellExecute = false` and `p.StanardInput.Write()` to send data to the process. If the process echoes the data, you're good, but you can't just hijack the process and use its StandardOutput handle as your own.
Jake
@spoulson: By "tee", do you mean that if I have a line of code "Console.Writeline("Hello,world")", the string output is written to both my program's StdOut and the Console's screen buffer? What's the point of this strange paradigm?
smwikipedia
@smwikipedia: If you're familiar with the unix `tee` command, it pipes StdOut from a process and writes to both Console and a file. It sounds like this is what you're trying to do.
spoulson
+2  A: 

You can get a hold of the application's stdout by calling Console.OpenStandardOutput. From there, you can do whatever you want with the stream, although you won't be able to reassign it. If you want to do that you'll have to P/Invoke SetStdHandle and handle the details yourself.

EDIT: Added example code for the P/Invoke route:

[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetStdHandle(int nStdHandle, IntPtr nHandle);

const int STD_OUTPUT_HANDLE = -11;

static void RedirectStandardOutput(FileStream file)
{
    SetStdHandle(STD_OUTPUT_HANDLE, file.SafeFileHandle.DangerousGetHandle());
}
MikeP
Thanks, MikeP. I'm wondering why let Console class claim the OpenStandardOutput() method, why not categorize this method under Process class, I think that would be more reasonable. What kind of design philosophy is involved?
smwikipedia
I don't know why they chose this method.
MikeP
+2  A: 

You probably shouldn't set the stdout of your own process. The reason it's stdout is so that the caller (command line, whatever) can redirect it wherever it needs to, without your program having to know.

That's how things like "type foo.txt | more" work. If the type command felt free to redefine stdout to a file, that wouldn't work at all.

If you want to write to a stream, just open the stream and write to it.

kyoryu