如何写一个字符串到Scala进程? [英] How to write a string to Scala Process?

查看:78
本文介绍了如何写一个字符串到Scala进程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开始并正在运行一个Scala进程.

I start and have running a Scala process.

    val dir = "/path/to/working/dir/"
    val stockfish = Process(Seq("wine", dir + "stockfish_8_x32.exe"))
    val logger = ProcessLogger(printf("Stdout: %s%n",  _))
    val stockfishProcess = stockfish.run(logger, connectInput = true)

该过程读取和写入标准IO(控制台).如果已经启动了一个字符串命令,该如何将其发送给该进程?

The process reads from and writes to standard IO (console). How can I send a string command to the process if it's been already started?

Scala流程API具有ProcessBuilder,该流程又具有许多有用的方法.但是,之前使用了ProcessBuilder,过程开始编写复杂的Shell命令.Scala还具有ProcessIO来处理输入或输出.我也不需要我只需要向进程发送消息即可.

Scala process API has ProcessBuilder which has in turn bunch of useful methods. But ProcessBuilder is used before a process starts to compose complex shell commands. Also Scala has ProcessIO to handle input or output. I don't need it too. I just need to send message to my process.

在Java中,我会做类似的事情.

In Java I would do something like this.

        String dir = "/path/to/working/dir/";
        ProcessBuilder builder = new ProcessBuilder("wine", dir + "stockfish_8_x32.exe");
        Process process = builder.start();

        OutputStream stdin = process.getOutputStream();
        InputStream stdout = process.getInputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(stdout));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));

        new Thread(() -> {
            try {
                String line;
                while ((line = reader.readLine()) != null) {
                    System.out.println("Stdout: " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        Thread.sleep(5000); // it's just for example
        writer.write("quit");  // send to the process command to stop working
        writer.newLine();
        writer.flush();

效果很好.我开始我的流程,从中获取InputStream和OutputStream,然后使用流与流程进行交互.

It works quite well. I start my process, get InputStream and OutputStream from it, and use the streams to interact with the process.

看来,Scala Process特性无法提供写入方法.流程运行后,ProcessBuilder无效.而ProcessIO仅用于IO捕获和处理.

It appears Scala Process trait provides no ways to write to it. ProcessBuilder is useless after process run. And ProcessIO is just for IO catching and handling.

有什么方法可以写入Scala运行过程吗?

Are there any ways to write to Scala running process?

更新:

我看不到如何使用ProcessIO将字符串传递给正在运行的进程.我做了以下事情.

I don't see how I may use ProcessIO to pass a string to running process. I did the following.

import scala.io.Source
import scala.sys.process._

object Sample extends App {

   def out = (output: java.io.OutputStream) => {
      output.flush()
      output.close()
   }

   def in = (input: java.io.InputStream) => {
      println("Stdout: " + Source.fromInputStream(input).mkString)
      input.close()
   }

   def go = {
      val dir = "/path/to/working/dir/"
      val stockfishSeq = Seq("wine", dir + "/stockfish_8_x32.exe")
      val pio = new ProcessIO(out, in, err => {})
      val stockfish = Process(stockfishSeq)
      stockfish.run(pio)

      Thread.sleep(5000)
      System.out.write("quit\n".getBytes)
      pio.writeInput(System.out) // "writeInput" is function "out" which I have passed to conforming ProcessIO instance. I can invoke it from here. It takes OutputStream but where can I obtain it? Here I just pass System.out for example.
   }
   go
 }

当然,它不起作用,而且我无法理解如何实现上述Java代码段中的功能.希望有Scala代码的建议或片段来解决我的问题.

Of course it does not work and I failed to understand how to implement functionality as in my Java snippet above. It would be great to have advice or snippet of Scala code clearing my issue.

推荐答案

以下是从流程获取输入和输出流的示例,您可以在流程启动后对其进行写入和读取:

Here is an example of obtaining input and output streams from a process, which you can write to and read from after the process starts:

object demo {
  import scala.sys.process._

  def getIO = {
    // create piped streams that can attach to process streams:
    val procInput = new java.io.PipedOutputStream()
    val procOutput = new java.io.PipedInputStream()
    val io = new ProcessIO(
      // attach to the process's internal input stream
      { in =>
        val istream = new java.io.PipedInputStream(procInput)
        val buf = Array.fill(100)(0.toByte)
        var br = 0
        while (br >= 0) {
          br = istream.read(buf)
          if (br > 0) { in.write(buf, 0, br) }
        }
        in.close()
      },
      // attach to the process's internal output stream
      { out =>
        val ostream = new java.io.PipedOutputStream(procOutput)
        val buf = Array.fill(100)(0.toByte)
        var br = 0
        while (br >= 0) {
          br = out.read(buf)
          if (br > 0) { ostream.write(buf, 0, br) }
        }
        out.close()
      },
      // ignore stderr
      { err => () }
    )
    // run the command with the IO object:
    val cmd = List("awk", "{ print $1 + $2 }")
    val proc = cmd.run(io)

    // wrap the raw streams in formatted IO objects:
    val procO = new java.io.BufferedReader(new java.io.InputStreamReader(procOutput))
    val procI = new java.io.PrintWriter(procInput, true)
    (procI, procO)
  }
}

这是使用输入和输出对象的简短示例.请注意,由于所有内容均已管道传输,缓冲等,因此很难保证在关闭输入流/对象之前该进程将接收其输入.

Here's a short example of using the input and output objects. Note that it's hard to guarantee that the process will receive it's input until you close the input streams/objects, since everything is piped, buffered, etc.

scala> :load /home/eje/scala/input2proc.scala
Loading /home/eje/scala/input2proc.scala...
defined module demo

scala> val (procI, procO) = demo.getIO
procI: java.io.PrintWriter = java.io.PrintWriter@7e809b79
procO: java.io.BufferedReader = java.io.BufferedReader@5cc126dc

scala> procI.println("1 2")

scala> procI.println("3 4")

scala> procI.println("5 6")

scala> procI.close()

scala> procO.readLine
res4: String = 3

scala> procO.readLine
res5: String = 7

scala> procO.readLine
res6: String = 11

scala> 

通常,如果您在同一线程中同时管理输入和输出,则有可能发生死锁,因为读或写都可能阻止等待对方.在自己的线程中运行输入逻辑和输出逻辑是最安全的.考虑到这些线程问题,也可以将输入和输出逻辑直接放入定义中....} 和 {out =>...} ,因为它们都自动在单独的线程中运行

In general, if you are managing both input and output simultaneously in the same thread, there is the potential for deadlock, since either read or write can block waiting for the other. It is safest to run input logic and output logic in their own threads. With these threading concerns in mind, it is also possible to just put the input and output logic directly into the definitions { in => ... } and { out => ... }, as these are both run in separate threads automatically

这篇关于如何写一个字符串到Scala进程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆