我正在编写一些需要使用外部命令行程序进行字符串转换的Scala代码。外部程序需要几分钟才能启动,然后侦听stdin上的数据(由换行符终止),转换数据,并将转换后的数据打印到stdout(再次由换行符终止)。它将永远存在,直到它收到SIGINT。
为简单起见,我们假设外部命令运行如下:
$ convert
input1
output2
input2
output2
$
convert
,input1
和input2
都是我输入的; output1
和output2
由程序写入stdout。我在最后输入了Control-C以返回shell。
在我的Scala代码中,我想启动这个外部程序,并让它在后台运行(因为启动成本很高,但一旦初始化就保持运行便宜),同时提供三种方法我的程序的其余部分使用API,如:
def initTranslation(): Unit
def translate(input: String): String
def stopTranslation(): Unit
initTranslation
应启动外部程序并使其在后台运行。
translate
应该将input
参数放在外部程序的stdin上(后跟换行符),等待输出(后跟换行符),然后返回输出。
stopTranslation
应该将SIGINT发送到外部程序。
之前我曾使用过Java和Scala外部进程管理,但是对Java管道没有太多经验,但我不能100%确定如何将这一切联系起来。特别是,我已经读过,当I / O管道在类似的情况下被连接时,有关于死锁的细微问题。我确定我需要一些Thread
来监视启动并监视initTranslation
中的后台进程,有些管道将String
发送到stdin,然后阻塞等待接收translate
中的数据和stdout上的换行符,然后是stopTranslation
中某种外部程序的终止。
我想用尽可能多的纯Scala来实现这一点,尽管我意识到这可能需要一些Java I / O库。我也不想使用任何第三方Scala或Java库(java。*,javax。*或scala。*之外的任何东西)
这三种方法会是什么样的?
答案 0 :(得分:0)
事实证明,这比我的预期要容易得多。我被各种帖子和建议(关于SO)误导了,这表明这会更复杂。
对此解决方案的注意事项:
var
存储局部变量。显然,var
不赞成使用最佳实践Scala,但是这个示例说明了所需的对象状态,您可以根据自己的喜好在自己的程序中构建变量。synchronized
关键字)来保护自己。解决方案:
import java.io.BufferedReader
import java.io.InputStreamReader
import java.lang.Process
import java.lang.ProcessBuilder
var process: Process = _
var outputReader: BufferedReader = _
def initTranslation(): Unit = {
process = new ProcessBuilder("convert").start()
outputReader = new BufferedReader(new InputStreamReader(process.getInputStream()))
}
def translate(input: String): String = {
// write path to external program
process.getOutputStream.write(cryptoPath.getBytes)
process.getOutputStream.write(System.lineSeparator.getBytes)
process.getOutputStream.flush()
// wait for input from program
outputReader.readLine()
}
def stopTranslation(): Unit = {
process.destroy()
}