Interact (i / o) with external process in Scala

I'm looking for an easy way to start an external process and then write lines to my input and read its output.

In Python, this works:

mosesProcess = subprocess.Popen([mosesBinPath, '-f', mosesModelPath], stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE);

# ...

mosesProcess.stdin.write(aRequest);
mosesAnswer = mosesProcess.stdout.readline().rstrip();

# ...

mosesProcess.stdin.write(anotherRequest);
mosesAnswer = mosesProcess.stdout.readline().rstrip();

# ...

mosesProcess.stdin.close();

      

I think in Scala this should be done with scala.sys.process.ProcessBuilder and scala.sys.process.ProcessIO , but I don't know "How they work (especially the latter).

EDIT:

I've tried things like:

val inputStream = new scala.concurrent.SyncVar[java.io.OutputStream];
val outputStream = new scala.concurrent.SyncVar[java.io.InputStream];
val errStream = new scala.concurrent.SyncVar[java.io.InputStream];

val cmd = "myProc";

val pb = process.Process(cmd);
val pio = new process.ProcessIO(stdin => inputStream.put(stdin),
  stdout => outputStream.put(stdout),
  stderr => errStream.put(stderr));

pb.run(pio);

inputStream.get.write(("request1" + "\n").getBytes);

println(outputStream.get.read); // It is blocked here

inputStream.get.write(("request2" + "\n").getBytes);

println(outputStream.get.read);

inputStream.get.close()

      

But the execution got stuck.

+3


source to share


3 answers


Of course, the attribute below is not a great example on the write side. I have an EchoServer that will input / output

    import scala.sys.process._
    import java.io._

    object EchoClient{
      def main(args: Array[String]) {
        var bContinue=true
        var cmd="C:\\\\windows\\system32\\attrib.exe"
        println(cmd)

        val process = Process (cmd)
        val io = new ProcessIO (
           writer,
           out => {scala.io.Source.fromInputStream(out).getLines.foreach(println)},
           err => {scala.io.Source.fromInputStream(err).getLines.foreach(println)})

        while (bContinue) {
          process run io
          var answer = readLine("Run again? (y/n)? ")
          if (answer=="n" || answer=="N")
            bContinue=false
        }
      }
      def reader(input: java.io.InputStream) = {
        // read here
      }

      def writer(output: java.io.OutputStream) = {
        // write here
        // 
      }

      // TODO: implement an error logger
    }

      



below :

C:\\windows\system32\attrib.exe
A            C:\dev\EchoClient$$anonfun$1.class
A            C:\dev\EchoClient$$anonfun$2$$anonfun$apply$1.class
A            C:\dev\EchoClient$$anonfun$2.class
A            C:\dev\EchoClient$$anonfun$3$$anonfun$apply$2.class
A            C:\dev\EchoClient$$anonfun$3.class
A            C:\dev\EchoClient$.class
A            C:\dev\EchoClient.class
A            C:\dev\EchoClient.scala
A            C:\dev\echoServer.bat
A            C:\dev\EchoServerChg$$anonfun$main$1.class
A            C:\dev\EchoServerChg$.class
A            C:\dev\EchoServerChg.class
A            C:\dev\EchoServerChg.scala
A            C:\dev\ScannerTest$$anonfun$main$1.class
A            C:\dev\ScannerTest$.class
A            C:\dev\ScannerTest.class
A            C:\dev\ScannerTest.scala
Run again? (y/n)?

      

+2


source


Scala API for ProcessIO :

new ProcessIO(in: (OutputStream) ⇒ Unit, out: (InputStream) ⇒ Unit, err: (InputStream) ⇒ Unit)

      

I assume you must provide at least two arguments, 1 outputStream function (write to process), 1 function inputStream (read from process).

For example:



def readJob(in: InputStream) { 
    // do smthing with in 
}
def writeJob(out: OutputStream) { 
     // do somthing with out
}
def errJob(err: InputStream) { 
    // do smthing with err 
}
val process = new ProcessIO(writeJob, readJob, errJob)

      

Please keep in mind that streams are Java streams, so you will need to check the Java API.

Edit: the page contains examples, maybe you can take a look at them.

+1


source


ProcessIO is the way to go for low level control and I / O interaction. Even the often missing BasicIO helper object is missing to help create shared ProcessIO instances for reading, connecting I / O streams with utility functions. You can look at the BasicIO.scala source to see what it does internally when instantiating ProcessIO.

Sometimes you can find inspiration from test cases or tools built for the class itself by the project. In the case of Scala, look at the source on GitHub. We're lucky to have a detailed ProcessIO example that is used for the scala GraphWiz Dot runner DotRunner.scala !

+1


source







All Articles