首先,我正在学习scala和java世界的新手。 我想创建一个控制台并将此控制台作为可以启动和停止的服务运行。 我能够将ConsoleReader运行到Actor中,但我不知道如何正确地停止ConsoleReader。 这是代码:
import eu.badmood.util.trace
import scala.actors.Actor._
import tools.jline.console.ConsoleReader
object Main {
def main(args:Array[String]){
//start the console
Console.start(message => {
//handle console inputs
message match {
case "exit" => Console.stop()
case _ => trace(message)
}
})
//try to stop the console after a time delay
Thread.sleep(2000)
Console.stop()
}
}
object Console {
private val consoleReader = new ConsoleReader()
private var running = false
def start(handler:(String)=>Unit){
running = true
actor{
while (running){
handler(consoleReader.readLine("\33[32m> \33[0m"))
}
}
}
def stop(){
//how to cancel an active call to ConsoleReader.readLine ?
running = false
}
}
我也在寻找有关此代码的任何建议!
答案 0 :(得分:3)
从输入中读取字符的基础调用是阻塞的。在非Windows平台上,它将使用System.in.read()
,在Windows上,它将使用org.fusesource.jansi.internal.WindowsSupport.readByte
。
所以你的挑战是当你想要停止你的控制台服务时,让阻止调用返回。有关一些想法,请参阅http://www.javaspecialists.eu/archive/Issue153.html和Is it possible to read from a InputStream with a timeout? ...一旦弄明白,当控制台服务停止时,让read
返回-1
,以便ConsoleReader
认为完成。您需要ConsoleReader
才能使用您的通话版本:
tools.jline.AnsiWindowsTerminal
并使用ConsoleReader
的{{1}}构造函数(否则Terminal
只会使用WindowsSupport。 readByte`直接)AnsiWindowsTerminal
构造函数需要ConsoleReader
,您可以在InputStream
还有一些想法:
System.in
对象,所以为了减少混淆,请用不同的名称命名。scala.Console
是一种独特的资源,因此您可能需要确保一次只有一位来电者使用System.in
。现在Console.readLine
会直接拨打start
,多个来电者可以拨打readLine
。可能控制台服务可以start
并维护一个处理程序列表。答案 1 :(得分:1)
假设ConsoleReader.readLine响应线程中断,您可以重写Console以使用一个线程,然后您可以中断该线程以阻止它。
object Console {
private val consoleReader = new ConsoleReader()
private var thread : Thread = _
def start(handler:(String)=>Unit) : Thread = {
thread = new Thread(new Runnable {
override def run() {
try {
while (true) {
handler(consoleReader.readLine("\33[32m> \33[0m"))
}
} catch {
case ie: InterruptedException =>
}
}
})
thread.start()
thread
}
def stop() {
thread.interrupt()
}
}
答案 2 :(得分:0)
您可以覆盖您的ConsoleReader InputStream。恕我直言,这是合理的,因为STDIN是一个“慢”流。请根据您的需求改进示例。这只是草图,但它有效:
def createReader() =
terminal.synchronized {
val reader = new ConsoleReader
terminal.enableEcho()
reader.setBellEnabled(false)
reader.setInput(new InputStreamWrapper(reader.getInput())) // turn on InterruptedException for InputStream.read
reader
}
使用InputStream包装器:
class InputStreamWrapper(is: InputStream, val timeout: Long = 50) extends FilterInputStream(is) {
@tailrec
final override def read(): Int = {
if (is.available() != 0)
is.read()
else {
Thread.sleep(timeout)
read()
}
}
}
P.S。我试图使用NIO - System.in(特别是跨平台)的许多麻烦。我回到了这个变种。 CPU负载接近0%。这适用于这种交互式应用程序。