Hi.
I'm trying to use NIO Channels to transfer files using Smack.
Basically, this is the code for retrieving a file and writing it into a file on the local machine:
FileChannel fc = new FileOutputStream(filename).getChannel();
InputStream in = request.accept().recieveFile();ReadableByteChannel rbc = java.nio.channels.Channels.newChannel(in); long pos = 0L; while (true) { long transferred = fc.transferFrom(rbc, pos, 99999999); if (transferred == 0) { // check for EOF
if (in.read() == -1) break; // <== IOException "Stream is closed"
} else pos += transferred; }
Note, that this code is just for illustration purposes -- the real code has no access to the FileTransferRequest nor the IncomingFileTransfer.
Unfortunately, with transferFrom, there's no indication as to whether the stream already reached EOF. That's why an extra check is used in order to break out of the loop when that happens.
For any other kind of stream, this code works very well. But, an IBBInputStream behaves special, because it gets auto-closed when it hits EOF, which is quite annoying.
Usually, for any InputStream if you reach EOF, the stream stays open, one can call read() ad nauseam which will always return -1.
I suggest that the implementation should be changed to differentiate between EOF and the closed state and, in particular, that a stream is only ever in the closed state after explicitely calling its close method.
\edit: here's the corresponding stack trace:
[java.io.IOException: Stream is closed at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession$IBBInputStream.checkClosed(InBandBytestreamSession.java:395) at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession$IBBInputStream.read(InBandBytestreamSession.java:305) at java.nio.channels.Channels$ReadableByteChannelImpl.read(Channels.java:385) at sun.nio.ch.FileChannelImpl.transferFromArbitraryChannel(FileChannelImpl.java:617) at sun.nio.ch.FileChannelImpl.transferFrom(FileChannelImpl.java:655)