sys.process将进程包装为函数

sch*_*mmd 8 scala

我有一个外部流程,我想将其视为一个函数String=>String.给定一行输入,它将以单行输出响应.看来我应该使用scala.sys.process,这显然是一个优雅的库,可以从scala中轻松访问许多shell操作.但是,我无法弄清楚如何执行这个简单的用例.

如果我向进程'stdin写一行,它会将结果打印在一行中.我如何使用sys.process创建包装器,以便我可以交互使用该过程?例如,如果我有一个实现ProcessWrapper,这是一个程序,它的输出:

// abstract definition
class ProcessWrapper(executable: String) {
  def apply(line: String): String
}

// program using an implementation
val process = new ProcessWrapper("cat -b")
println(process("foo"))
println(process("bar"))
println(process("baz"))
Run Code Online (Sandbox Code Playgroud)

输出:

 1  foo
 2  bar
 3  baz
Run Code Online (Sandbox Code Playgroud)

重要的是不要为每次调用重新加载进程,process因为存在重要的初始化步骤.

mic*_*l_s 3

所以 - 在我发表评论之后 - 这将是我的解决方案

import java.io.BufferedReader
import java.io.File
import java.io.InputStream
import java.io.InputStreamReader

import scala.annotation.tailrec

class ProcessWrapper(cmdLine: String, lineListenerOut: String => Unit, lineListenerErr: String => Unit,
                     finishHandler: => Unit,
                     lineMode: Boolean = true, envp: Array[String] = null, dir: File = null) {

  class StreamRunnable(val stream: InputStream, listener: String => Unit) extends Runnable {
    def run() {
      try {
        val in = new BufferedReader(new InputStreamReader(this.stream));
        @tailrec
        def readLines {
          val line = in.readLine
          if (line != null) {
            listener(line)
            readLines
          }
        }
        readLines
      }
      finally {
        this.stream.close
        finishHandler
      }
    }
  }
  val process = Runtime.getRuntime().exec(cmdLine, envp, dir);
  val outThread = new Thread(new StreamRunnable(process.getInputStream, lineListenerOut), "StreamHandlerOut")
  val errThread = new Thread(new StreamRunnable(process.getErrorStream, lineListenerErr), "StreamHandlerErr")
  val sendToProcess = process.getOutputStream
  outThread.start
  errThread.start

  def apply(txt: String) {
    sendToProcess.write(txt.getBytes)
    if (lineMode)
      sendToProcess.write('\n')
    sendToProcess.flush
  }

}

object ProcessWrapper {
  def main(args: Array[String]) {
    val process = new ProcessWrapper("python -i", txt => println("py> " + txt),
      err => System.err.println("py err> " + err), System.exit(0))
    while (true) {
      process(readLine)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

主要部分是 StreamRunnable,其中在线程中读取进程,并将接收到的行传递给“LineListener”(一个简单的 String => Unit - 函数)。主要只是一个示例实现 - 调用 python ;)