我开始运行Scala进程。
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(控制台)读取和写入。如果已经启动过该字符串命令,该怎么办?
Scala进程API具有ProcessBuilder,而ProcessBuilder又有许多有用的方法。但ProcessBuilder在之前进程开始组成复杂的shell命令。 Scala还有ProcessIO来处理输入或输出。我也不需要它。我只需要向我的流程发送消息。
在Java中我会做这样的事情。
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,并使用流与进程交互。
似乎Scala Process trait没有提供写入它的方法。进程运行后,ProcessBuilder无用。而ProcessIO只是用于IO捕获和处理。
有没有办法写Scala运行过程?
更新
我不知道如何使用ProcessIO将字符串传递给正在运行的进程。 我做了以下。
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代码的建议或片段清除我的问题。
答案 0 :(得分:1)
我认为围绕Scala进程的文档(特别是ProcessIO
的用法和语义)可以使用一些改进。我第一次尝试使用这个API时,我发现它非常混乱,并且需要一些试验和错误才能使我的子进程i / o正常工作。
我认为看到一个简单的例子可能就是你真正需要的。我会做一些非常简单的事情:调用bc
作为子进程来进行一些简单的计算,然后将答案打印到我的标准输出。我的目标是做这样的事情(但是来自Scala,而不是来自我的shell):
$ printf "1+2\n3+4\n" | bc
3
7
以下是我在Scala中的表现:
import scala.io.Source
import scala.sys.process._
object SimpleProcessExample 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()
}
// limit scope of any temporary variables
locally {
val calcCommand = "bc"
// strings are implicitly converted to ProcessBuilder
// via scala.sys.process.ProcessImplicits.stringToProcess(_)
val calcProc = calcCommand.run(new ProcessIO(
// Handle subprocess's stdin
// (which we write via an OutputStream)
in => {
val writer = new java.io.PrintWriter(in)
writer.println("1 + 2")
writer.println("3 + 4")
writer.close()
},
// Handle subprocess's stdout
// (which we read via an InputStream)
out => {
val src = scala.io.Source.fromInputStream(out)
for (line <- src.getLines()) {
println("Answer: " + line)
}
src.close()
},
// We don't want to use stderr, so just close it.
_.close()
))
// Using ProcessBuilder.run() will automatically launch
// a new thread for the input/output routines passed to ProcessIO.
// We just need to wait for it to finish.
val code = calcProc.exitValue()
println(s"Subprocess exited with code $code.")
}
}
请注意,您实际上并未直接调用ProcessIO
对象的任何方法,因为它们会被ProcessBuilder
自动调用。
结果如下:
$ scala SimpleProcessExample
Answer: 3
Answer: 7
Subprocess exited with code 0.
如果您希望输入和输出处理程序与子进程之间进行交互,则可以使用标准线程通信工具(例如,两者都关闭BlockingQueue
的实例)。
答案 1 :(得分:0)
我实际上没有尝试过这个,但documentation表示你可以使用ProcessIO的实例来处理Process的输入和输出,其方式与在Java中的方式类似。
答案 2 :(得分:0)
以下是从流程获取输入和输出流的示例,您可以在流程开始后写入和读取:
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)
}
}
这是使用输入和输出对象的简短示例。请注意,在关闭输入流/对象之前,很难保证进程将接收它的输入,因为所有内容都是管道,缓冲等。
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>
通常,如果在同一个线程中同时管理输入和输出,则可能存在死锁,因为读取或写入都可能阻塞等待另一个。在自己的线程中运行输入逻辑和输出逻辑是最安全的。考虑到这些线程问题,也可以将输入和输出逻辑直接放入定义{ in => ... }
和{ out => ... }
中,因为它们都在不同的线程中自动运行
答案 3 :(得分:0)
var outPutStream: Option[OutputStream] = None
val io = new ProcessIO(
{ outputStream =>
outPutStream = Some(outputStream)
},
Source.fromInputStream(_).getLines().foreach(println),
Source.fromInputStream(_).getLines().foreach(println)
)
command run io
val out = outPutStream.get
out.write("test" getBytes())
你可以用同样的方式得到一个 InputStream。