Welcome! Please see the About page for a little more info on how this works.

0 votes
ago in IO by
closed ago by

I've noticed that the clojure.java.io namespace's code includes a very common mistake when reading InputStreams. Your typical do-copy will have some variation of this loop:

`
(let [buffer (make-array Byte/TYPE (buffer-size opts))]

(loop []
  (let [size (.read input buffer)]
    (when (pos? size)
      (do (.write output buffer 0 size)
          (recur))))))

`

It is incorrect to say when (pos? size) because the InputStream interface has this definition for read method return:

Returns: the total number of bytes read into the buffer, or -1 if there is no more data because the end of the stream has been reached.

Yes, it is perfectly legal for read to return 0 bytes read when the stream is not at the end yet.

I guess they made it like that so that you can return 0 bytes from a socket that is stalled and enable the caller to timeout or abort or do something else.

In any case the correct condition for detecting end of stream is to compare the return to -1.

1 Answer

0 votes
ago by
selected ago by
 
Best answer

The docstring of the interface method also mentions:

 * <p> If the length of {@code b} is zero, then no bytes are read and
 * {@code 0} is returned; otherwise, there is an attempt to read at
 * least one byte. If no byte is available because the stream is at the
 * end of the file, the value {@code -1} is returned; otherwise, at
 * least one byte is read and stored into {@code b}.

So it can return 0 iff the buffer size is 0.

...