C# 将处理结果重定向到文本文件

C# Redirecting process results to a text file

我一直在绞尽脑汁想弄清楚为什么我不能使用 >>(追加)作为我 p.StartInfo.Argument 的一部分。当我删除“>”时,它工作得很好,但当我尝试使用“>”或“>>”时,我收到 "Incorrect Parameter" 错误。我已经继续编写没有 > 或 >> 的程序,只是将输出存储到一个字符串中,稍后将其写入文件。有人可以解释为什么“>”或“>>”在这种情况下不起作用吗?

// 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();

那是因为 >>> 不是 attrib.exe 解释的参数,它们是 cmd.exe.

的指令

你可以试试这样的东西:

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

此外,这是一条红鲱鱼:

p.StartInfo.RedirectStandardOutput = true;

如果您想以 C# 代码读取输出并自己编写文件,则可以使用此选项。使用 > 输出重定向器没有帮助。

输出重定向运算符 >cmd.exe 的功能,而不是操作系统。因此,使用它的天真方法是这样调用 cmd

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

但是,重定向输出的正确方法是首先将 StartInfo.RedirectStandardOutput 设置为 true(您这样做了),然后将 Process.StandardOutput 的输出通过管道传输到文件,因此:

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

或者,异步版本:

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

SlugFiller 的解决方案很好,但不能可靠地处理大量输出。问题是,如果进程输出太多文本,它就会挂起,因为流达到了最大缓冲区大小。换句话说,流需要在进程运行时被假脱机,防止缓冲区被填满。

但是,有一种方法可以使用任务从输出流接收数据并在 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();
    }
}

在某些时候一定要调用 stdoutThread.Join() 以确保线程完成。我已经用一些生成大量输出的代码对此进行了测试,它仍然有可能溢出缓冲区,或者用极长的行打破 ReadLine(),但它确实适用于几千个数量级的非常快的输出每秒 80 个字符行。