Reputation: 1613
How do you detect non-empty standard input (*in*
) without reading from it in a non-blocking way in Clojure?
At first, I thought calling using the java.io.Reader#ready()
method would do, but (.ready *in*)
returns false
even when standard input is provided.
Upvotes: 4
Views: 480
Reputation: 1688
Is this what you are looking for? 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
Update: It does seem that .available
is a race condition checking STDIN. n alternative is to have a fixed timeout for STDIN to become available otherwise assume no data is coming from STDIN
Here is an example of using core.async to attempt to read the first byte from STDIN and append it to the rest of the STDIN or timeout.
(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"))))
Upvotes: 4
Reputation: 29958
Have you looked at PushbackReader? You can use it like:
https://docs.oracle.com/javase/8/docs/api/index.html?java/io/PushbackReader.html
If you need it to be non-blocking stick it into a future
, a core.async
channel, or similar.
Upvotes: 0