_Original issue created by [email protected] on 2011-04-05 at 05:34 PM_
NIO already provides a way to convert {Readable,Writable}ByteChannel instances to {Input,Output}Stream, respectively. It does not provide that sort of interface for a ByteBuffer, however.
The attached classes provide a way to view a ByteBuffer as an InputStream or OutputStream, including an implementation of the DataInput and DataOutput interfaces respectively (which make use of the ByteBuffer's own endianness setting). This makes it possible to link legacy code using any of these interfaces to a NIO ByteBuffer.
This becomes even more useful in the context of a MappedByteBuffer, which functions as a ByteBuffer rather than a Channel. Via the classes contributed here, it's possible for the same java.io-compatible code to work on "plain" streams or memory-mapped files regardless of backing implementation. To add to this capability, ByteBufferDataOutputStream.flush() will call MappedByteBuffer.force() if the buffer is mapped.
Technical note: The weird-looking convertException() bit exists to make these classes function more like the java.io equivalents. It catches the (unchecked) Buffer*Exception instances, and throws a checked EOFException instead. For simplicity, and to avoid synchronization overhead, NullPointerException -- which should only happen when the internal "buf" has been nulled out by close() -- is also caught and converted to a ClosedChannelException, a subclass of IOException.
_Original comment posted by [email protected] on 2011-04-05 at 05:39 PM_
Revision: added Preconditions.checkNotNull() at the top of all methods accepting a reference argument, so that those don't get converted to ClosedChannelException.
I did not add this to the ctors, as that's arguably a valid use case (the stream is closed already at constructor time). That check could be added if desired, though.
_Original comment posted by [email protected] on 2011-07-13 at 07:43 PM_
I don't know if the ByteBufferDataInputStream is the way we want to address the problem or not, but we do want to make sure that _something_ is covering this use case properly.
Status: Accepted
Labels: Type-Enhancement
_Original comment posted by [email protected] on 2011-07-13 at 07:43 PM_
_(No comment entered for this change.)_
_Original comment posted by [email protected] on 2011-07-13 at 07:50 PM_
It seemed to be the natural place to offer this conversion. Channels are already convertible to stream via the static methods in java.nio.channel.Channels, but there's no prefab way to convert a buffer (such as would be obtained when mmap'ing a file).
Nobody is required to use the DataInput/DataOutput interfaces; I added them as a logical-to-me extension, because a ByteBuffer already has notions of endianness and data conversion built-in. They function fine as bare {Input,Output}Stream instances too.
_Original comment posted by [email protected] on 2011-12-10 at 04:04 PM_
_(No comment entered for this change.)_
Labels: Package-IO
_Original comment posted by [email protected] on 2012-05-30 at 07:43 PM_
_(No comment entered for this change.)_
Labels: -Type-Enhancement, Type-Addition
_Original comment posted by michael.deardeuff on 2012-12-24 at 11:48 AM_
A few things about the implementation of the InputStream as given.
First, it is trivial to support the mark/reset/markSupported operations. Might as well throw them in.
Also, it might be nice to have the classes extend Buffered{Input,Output}Stream. Because they are in fact buffered.
There is an issue with those pesky superclass fields, though. If you don't mind extra ints/null references hanging around, then you can use this constructor:
ByteBufferInputStream(ByteBuffer buffer) {
super(null, 1);
this.buf = buffer;
super.buf = null;
}
_Original comment posted by [email protected] on 2012-12-24 at 09:17 PM_
As for mark/reset, I actually have no idea why I didn't implement those. Probably an oversight. Yes, they can be implemented.
On subclassing: I chose Data{Input,Output}Stream as those classes are well-known to a lot of third party code, and are actually used in the method signatures of some methods. (Sure, in theory they should use generics, e.g. extends DataInput & Flushable & Closeable>, but that's still not commonplace. Plenty of code directly requests a Data*Stream.)
I've yet to see any code that actually cares about seeing a BufferedInputStream or BufferedOutputStream -- these seem only useful as add-in layers to implement buffering under the hood, not as a capability-marking class. I think it would be a bit of a mistake to extend those, since the superclass's buffering isn't going to be used anyway.
_Original comment posted by michael.deardeuff on 2012-12-24 at 10:07 PM_
I'm not sold on the BufferedInputStream either, I was just implementing a ByteSource based on an array of ByteBuffers and had just coded up BufferInputStream when I noticed ByteSource has openBufferedStream(). I was just throwing the idea out there.
I think good use would check for markSupported() instead of instanceof BufferedInputStream; but then again, ByteSource doesn't.
_Original comment posted by pjulien on 2013-02-02 at 04:54 PM_
I find it strange that these classes don't do more to manager the mark, e.g., I would have expected the byte buffer to be exactly as it was, mark and all, after closing the input stream
Is there an ETA for when this might get into guava? I note that kryo, zookeeper, and kafka all have their own implementations of ByteBufferInputStream
Most helpful comment
Is there an ETA for when this might get into guava? I note that kryo, zookeeper, and kafka all have their own implementations of ByteBufferInputStream