【问题标题】:Detect non-empty STDIN in Clojure在 Clojure 中检测非空的 STDIN
【发布时间】:2017-01-10 18:03:35
【问题描述】:

如何在 Clojure 中检测非空标准输入 (*in*) 而不以非阻塞方式读取它?

一开始,我以为使用java.io.Reader#ready() 方法调用就可以了,但是即使提供了标准输入,(.ready *in*) 也会返回false

【问题讨论】:

  • 你会如何在 Java 中做到这一点?然后,您可以只使用 Java 互操作。
  • 我也寻找过 Java 解决方案,但可惜没有找到。
  • 这个用例是什么?最简单的答案是使用一个单独的线程,只做阻塞读取。
  • 用例是检测程序是否在标准输入上提供了一些数据。如果是这种情况,则程序读取提供的数据,否则继续。

标签: clojure stdin


【解决方案1】:

这就是你要找的吗? InputStream .available

(defn -main [& args]
  (if (> (.available System/in) 0)
    (println "STDIN: " (slurp *in*))
    (println "No Input")))

$ echo "hello" | lein run
STDIN:  hello

$ lein run
No Input

更新.available 似乎确实是检查 STDIN 的竞争条件。另一种方法是为 STDIN 提供一个固定的超时时间,否则假设没有数据来自 STDIN

这是一个使用 core.async 尝试从 STDIN 读取第一个字节并将其附加到 STDIN 的其余部分或超时的示例。

(ns stdin.core
  (:require
   [clojure.core.async :as async :refer [go >! timeout chan alt!!]])
  (:gen-class))

(defn -main [& args]
  (let [c (chan)]
    (go (>! c (.read *in*)))
    (if-let [ch (alt!! (timeout 500) nil
                       c ([ch] (if-not (< ch 0) ch)))]
      (do
        (.unread *in* ch)
        (println (slurp *in*)))

      (println "No STDIN")))) 

【讨论】:

  • 我以前试过这个,但似乎不起作用。你的例子就像我想要的那样工作。我会再调查一下。
  • 我不确定这是否可行。有关类似问题的良好描述,请参阅此答案stackoverflow.com/a/12384207/3438870
  • 展开,我确实看到了和你一样的行为。我的猜测是操作系统向标准输入添加数据和应用程序检查之间存在竞争条件。我做了一些更多的测试,如果我在两次检查之间以 10 毫秒的睡眠时间检查几次,则有些情况下标准输入中没有数据,然后它变为可用。这可以追溯到你原来的问题,它并不是真正的确定性。您可以阻塞一段时间,如果 stdin 上没有显示任何内容,则假设没有任何内容会继续前进。
  • 通过调用.unread 是的,但似乎未读的工作方式是您必须提供要未读的内容。 reset 总是从 java 文档中抛出异常“PushbackReader 的重置方法总是抛出异常。”您不能在读取后简单地重置流。
  • 这更多的是|如何工作的问题。 lein run 的两个进程与| 的左侧并行运行,将 STDOUT 发送到右侧的 STDIN。两者都有一个固定的等待输入超时,随着进程并行执行,这是一个竞争条件,一个将首先完成。问题的一个例子是如果您运行(sleep 5 &amp;&amp; echo "hi") | lein run 这将始终显示“No STDIN”,因为在等待 STDIN 完成后调用了 echo。但是如果你运行 (sleep .1 &amp;&amp; echo "hi") | lein run 你应该总是得到 STDIN。
【解决方案2】:

你看过 PushbackReader 吗?你可以像这样使用它:

  1. 读取一个字节(阻塞)。如果流已关闭,则返回 char read 或 -1。
  2. 返回时,您知道一个字节已准备好。
  3. 如果字节是你还没有准备好的东西,把它放回去
  4. 如果流已关闭(-1 返回值),则退出。
  5. 重复。

https://docs.oracle.com/javase/8/docs/api/index.html?java/io/PushbackReader.html

如果您需要它是非阻塞的,请将其粘贴到 futurecore.async 频道或类似频道中。

【讨论】:

  • 我试过了,但发现你无法从 STDIN 中读取一个字节。此外,这会阻塞直到提供输入,因此需要结合超时。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-05
  • 2013-12-16
  • 1970-01-01
  • 2017-10-03
  • 2014-06-14
  • 1970-01-01
相关资源
最近更新 更多