通过 C# 从 RScript 捕获标准输出

capturing stdout from RScript via C#

我正在尝试 运行 使用位于 R 安装的 \bin\ 目录中的 RScript.exe 的 R 脚本。 运行 windows 命令行中的 RScript 将结果写入屏幕。当我尝试使用 System.Diagnostics.Process() 在 C# 中进行复制时,输出似乎丢失了。

举个简单的例子,我将忽略我的实际 r 代码,只尝试从 RScript.exe 读取版本信息。当 运行 来自 cmd 提示符时:

rscript --version

我在屏幕上看到了

R scripting front-end version 3.2.3 (2015-12-10)

当我在此 C# 代码中执行相同操作时,没有捕获任何内容。

StringBuilder outputBuilder = new StringBuilder();

System.Diagnostics.Process proc = new System.Diagnostics.Process();

proc.StartInfo.FileName = "rscript";
proc.StartInfo.RedirectStandardError = true;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.ErrorDialog = false;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.Arguments = "--version";
proc.EnableRaisingEvents = true;

proc.OutputDataReceived += new DataReceivedEventHandler
(
    delegate(object sender, DataReceivedEventArgs e)
    {
        outputBuilder.Append(e.Data);
    }
);
proc.ErrorDataReceived += new DataReceivedEventHandler
(
    delegate(object sender, DataReceivedEventArgs e)
    {
        outputBuilder.Append(e.Data);
    }
);

proc.Start();
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();

proc.WaitForExit();
string allOutput = outputBuilder.ToString();

看起来这应该很简单,但是尽管看了很多从 c# 捕获 stdout 的示例,但我仍然感到困惑。

按照下面的方法尝试。

使用Process.StandardOutput属性。 (您已经将 RedirectStandardOutput 设置为 true)。

这个returns一个StreamReader可以用来读取应用程序的标准输出流。

例如: 开始进程后..

string output = proc.StandardOutput.ReadToEnd();

查看下方 link 了解更多详情。

https://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput(v=vs.110).aspx

你必须在 WaitForExit() 之前打电话。以上link解释了大部分后果。

这最终对我有用,我不确定到底是什么问题,因为它看起来与原始版本几乎相同。

public void test()

    string exe = @"C:\Program Files\R\R-3.5.2\bin\x64\Rscript.exe";

    System.Diagnostics.Process proc = new System.Diagnostics.Process();
    ProcessStartInfo psi = new ProcessStartInfo();
    psi.WorkingDirectory = Path.GetDirectoryName(exe);
    psi.Arguments = "--version";
    psi.FileName = exe;

    psi.UseShellExecute = false;
    psi.RedirectStandardOutput = true;
    psi.RedirectStandardError = true;
    psi.CreateNoWindow = true;

    proc.StartInfo = psi;

    proc.ErrorDataReceived += consoleDataReceived;
    proc.OutputDataReceived += consoleDataReceived;
    proc.EnableRaisingEvents = true;
    proc.Start();
    proc.BeginOutputReadLine();
    proc.BeginErrorReadLine();

    while (!proc.HasExited)
    {
        Thread.Sleep(100);
    }

    //this flushes the rest of the messages out.
    proc.WaitForExit();
}

public void consoleDataReceived(object sender, DataReceivedEventArgs e)
{
    string strMessage = e.Data;
    Console.WriteLine(e.Data);
}