Java IO PushbackReader example in Clojure

A PushbackReader can wrap a stream from file, string or standard input. PushbackReader is usually used to implement a parser which need to read chars one by one from a source and may need to pushback chars back to the stream or look ahead.

For example the Clojure programming language, when you working in a REPL, everything you input are sent to Coljure through which then wrapped in a LineNumberingPushbackReader.

Create a PushbackReader

Let's define a PushbackReader on a String in Clojure

(def pbr ( ( ( (.getBytes "hello\n"))) ) )

And see what's inside a PushbackReader

user> show
(#<Method public int throws>
#<Method public int[],int,int) throws>
nil #<Method public void throws>
nil #<Method public void throws>
nil #<Method public boolean>
nil #<Method public void throws>
nil #<Method public long throws>
nil #<Method private void throws>
nil #<Method public boolean throws>
nil #<Method public void[]) throws>
nil #<Method public void throws>
nil #<Method public void[],int,int) throws>
nil nil)

Read a char from PushbackReader

The read method will retrieve a char from the stream and the stream move one char

user> (.read pbr)
user> (int \h)

The next call on read will return "e".

Pushback or unread a char to stream

Pushback a char will prepend to the front of the stream and move the stream one character backward.

(.unread pbr (int \a))

But if you unread it again, you will get overflow error

user> (.unread pbr (int \a))
IOException Pushback buffer overflow (

Why? Because by default the pushback buffer has length of one. Every time you execute unread, the pushback buffer is consumed and full, but one or more read will free the buffer.

Read and push back a string to stream

Sometime you may want to read or push back a whole string to stream, you need to set the push back buffer size larger than 1.

(def pbr ( ( ( (.getBytes "hello\n"))) 100) )

Read the whole string

    (loop [ch (.read pbr) acc ""]
      (if (= ch -1)
        (recur (.read pbr) (str (char ch) acc))

-1 means the EOF, if you want to read a line each time, set it to \newline

And push it back

(.unread pbr (char-array (str "hello, world")))