2

I've been racking my brain trying to figure out why I can not use >> (append) as a part of my p.StartInfo.Argument. When I remove ">" it works perfectly, but the moment I try to use ">" or ">>" I get a "Incorrect Parameter" error. I've gone ahead and wrote my program without > or >> and just stored the output into a string and write it to a file later. Could someone explain why ">" or ">>" would not work in this situation?

// Start the child process.
 Process p = new Process();
 // Redirect the output stream of the child process.
 p.StartInfo.UseShellExecute = false;
 p.StartInfo.RedirectStandardOutput = true;
 p.StartInfo.FileName = "attrib.exe";
startInfo.Arguments = "/S *.jpg > mypics.txt";

 p.Start();
snapplex
  • 851
  • 3
  • 13
  • 27

3 Answers3

2

The output redirection operator > is a feature of cmd.exe, not the operating system. The naive way to use it is hence to call cmd as so:

p.StartInfo.FileName = "cmd.exe";
startInfo.Arguments = "/C \"attrib.exe /S *.jpg > mypics.txt\"";

The proper way to redirect the output, however, is to first set StartInfo.RedirectStandardOutput to true (which you did), and then pipe the output from Process.StandardOutput to the file, as so:

using(StreamWriter file = new StreamWriter("mypics.txt")) {
    p.StandardOutput.CopyTo(file);
}

Or, async version:

using(StreamWriter file = new StreamWriter("mypics.txt")) {
    await p.StandardOutput.CopyToAsync(file);
}
SlugFiller
  • 1,596
  • 12
  • 12
  • I have not had a chance to try our your suggestion, but I'm eager to see if the double quotes will let me get away with using the redirection operator. – snapplex Apr 16 '15 at 21:44
  • It's not so much the double quotes, as it is the call to "cmd.exe". I actually recommend the latter version (using `StandardOutput.CopyTo`), which removes the dependency on "cmd.exe". – SlugFiller Apr 18 '15 at 13:17
1

That's because > and >> are not arguments interpreted by attrib.exe, they're instructions to cmd.exe.

You could try instead something like:

p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c attrib.exe /S *.jpg > mypics.txt";

Also, this is a red herring:

p.StartInfo.RedirectStandardOutput = true;

If you wanted to read the output in C# code and write the file yourself, you'd use this option. It's not helpful for using the > output redirector.

Blorgbeard
  • 101,031
  • 48
  • 228
  • 272
  • I wanted to use the redirect operator, but C# forced my hand and I did not want to make a batch file. – snapplex Apr 16 '15 at 21:43
0

SlugFiller's solution is good but doesn't work reliably with large amounts of output. The problem is that if the process outputs too much text it hangs because the stream reaches the maximum buffer size. In other words the stream needs to be spooled out as the process runs, preventing the buffer from ever filling up.

However, there is a way to do this using a task to receive data from the output stream and spool it out in real-time.

// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "attrib.exe";
startInfo.Arguments = "/S *.jpg > mypics.txt";
p.Start();


Thread stdoutThread = new Thread(new ThreadStart(WriteStandardOutput));
stdoutThread.IsBackground = true;
stdoutThread.Name = "stdout_writer";
stdoutThread.Start();

private void WriteStandardOutput()
{
    using (StreamWriter sw = File.CreateText(ConsoleLogFileFullPath))
    using (StreamReader sr = p.StandardOutput)
    {
        for (;;)
        {
            string line = sr.ReadLine();
            if (line == null)
                break;
            sw.WriteLine(textLine);
        }
        sw.Flush();
    }
}

At some point be sure to call stdoutThread.Join() to make sure that the thread completes. I have tested this with some code that generates large amounts of output and it's still possible to overflow the buffer, or to break ReadLine() with extremely long lines, but it does work for very fast output in the order of a few thousand 80 character lines per second.