Reading/Writing to a command line program in c#

2020-03-31 04:00发布

问题:

I'm trying to talk to a command-line program from C#. It is a sentiment analyser. It works like this:

CMD> java -jar analyser.jar

>Starting analyser...

{This is where I want to insert things from my c# program. For example:}

I love you!

{And the program responds - I want to read this}

Very Positive

Here's some pseudo code:

Process.start("sentiment.exe");
Process.writeline("I love you");
string Response = Process.readline();

What methods does C# offer for writing to a process's standard input and reading from a its standard output?

回答1:

What you're trying to do is to "redirect" the standard input and output channels for the process that you're launching. This will allow you to read from and write to the child process via C# streams.

To do so, you first need to set the RedirectStandardInput and RedirectStandardOutput fields in the ProcessStartInfo class you use to start the child process:

Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "otherprogram.exe";
p.Start();

Once that's done, p.StandardInput and p.StandardOutput will be StreamReaders that are attached to the input and output of the child process. Depending on the exact input and output of the child process, you may need to be careful to avoid deadlocking (where your program is waiting for output while the other program is waiting for input, as an example). To avoid that, you can use the BeginOutputReadLine method to receive output asynchronously, if needed.



回答2:

Here's a little demo showing how to do what you are asking.

This is a toy command line app that just reads from standard input and echos back to standard output:

class Echoer
{
    static void Main(string[] args)
    {
        while (true)
        {
            var input = Console.ReadLine();
            Console.WriteLine("Echoing: " + input);
        }
    }
}

This is another command line app that runs the above app, passing input to it, and reading its output:

class Program
{
    static void Main(string[] args)
    {
        ProcessStartInfo processStartInfo;
        processStartInfo = new ProcessStartInfo();
        processStartInfo.CreateNoWindow = true;

        // Redirect IO to allow us to read and write to it.
        processStartInfo.RedirectStandardOutput = true;
        processStartInfo.RedirectStandardInput = true;
        processStartInfo.UseShellExecute = false;

        processStartInfo.FileName = @"path\to\your\Echoer.exe";

        Process process = new Process();
        process.StartInfo = processStartInfo;
        process.Start();
        int counter = 0;
        while (counter < 10)
        {
            // Write to the process's standard input.
            process.StandardInput.WriteLine(counter.ToString());

            // Read from the process's standard output.
            var output = process.StandardOutput.ReadLine();
            Console.WriteLine("Hosted process said: " + output);
            counter++;
        }

        process.Kill();

        Console.WriteLine("Hit any key to exit.");
        Console.ReadKey();
    }
}

If the app you are hosting does not simply produce a line of output in response to a line of input, then you can look at capturing output asynchronously using Process.BeginOutputReadLine (there's example code in the linked documentation).



回答3:

This is not a general question, but rather a application-specific one. I just happened to be working on the same thing. We probably should not discuss about this here, but forgive me I just want to help.

The key point is that you need to enter the right arguments for the jar

var processInfo = new ProcessStartInfo("java.exe", "-jar SentiStrengthCom.jar stdin sentidata data201109/ scale"){ ... }

Below is a working solution:

    // Start the java server, probably in a background thread
    void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        string directory = ...; // the directory of jar

        var processInfo = new ProcessStartInfo("java.exe", "-jar SentiStrengthCom.jar stdin sentidata data201109/ scale")
        {
            // Initialize properties of "processInfo"
            CreateNoWindow = true,
            UseShellExecute = false, 
            WorkingDirectory = directory,
            RedirectStandardOutput = true,
            RedirectStandardError = true,
            RedirectStandardInput = true,
        };

        JavaSentiStrength = new Process();
        JavaSentiStrength.StartInfo = processInfo;

        JavaSentiStrength.Start();

        Console.WriteLine("SentiStrengthCom Java is running...");

        JavaSentiStrength.WaitForExit();

        int exitCode = 0;
        if (JavaSentiStrength != null) exitCode = JavaSentiStrength.ExitCode;
        Debug.WriteLine("Java SentiStrengthCom closed down! " + exitCode);
        JavaSentiStrength.Close();
        JavaSentiStrength = null;

    }

    // A button click
    private void btnRequest_Click(object sender, EventArgs e)
    {
        JavaSentiStrength.StandardInput.WriteLine("love you ");
        string s_out = JavaSentiStrength.StandardOutput.ReadLine();
        Debug.WriteLine("SentiStrengthCom output: " + s_out);
    }

The output is

SentiStrengthCom output: 3 -1 2

Hope it helps!



标签: c# shell cmd