11

まず第一に、私は 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
  }

}

このコードに関するアドバイスもお待ちしています。

4

3 に答える 3

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戻ってくるようにして、それが完了したと考えます。その呼び出しのバージョンを使用する必要があります。-1ConsoleReaderConsoleReader

  • Windows を使用している場合は、おそらくオーバーライドして、を受け取るコンストラクターをtools.jline.AnsiWindowsTerminal使用する必要があります(それ以外の場合は、 WindowsSupport.readByte` を直接使用するだけです) 。ConsoleReaderTerminalAnsiWindowsTerminal
  • UNIX では、 を受け取るConsoleReaderコンストラクタが 1 つありInputStreamます。独自のラッパーを提供できます。System.in

さらにいくつかの考え:

  • すでにオブジェクトがあるscala.Consoleので、混乱を避けるために別の名前を付けてください。
  • System.inは一意のリソースであるため、一度に 1 つの呼び出し元のみが使用するようにする必要がありますConsole.readLine。今すぐstart直接呼び出すreadLineと、複数の発信者が呼び出すことができますstart。おそらく、コンソール サービスreadLineはハンドラーのリストを維持できます。
于 2011-07-17T15:49:09.507 に答える
1

ConsoleReader.readLine がスレッドの中断に応答すると仮定すると、Console を書き換えて Thread を使用し、それを中断して停止することができます。

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()
  }

}
于 2011-07-18T18:37:52.047 に答える
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()
  }
}

}

PS私はNIOを使用しようとしました-System.in(特にクロスプラットフォーム)で多くの問題が発生しました。この変種に戻りました。CPU 負荷はほぼ 0% です。これは、このようなインタラクティブなアプリケーションに適しています。

于 2012-11-23T13:15:26.610 に答える