ByteReader.java
package space.sunqian.fs.io;
import space.sunqian.annotation.Nonnull;
import space.sunqian.annotation.Nullable;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
/**
* This interface represents the byte data reader to read byte data as {@link ByteSegment} from the data source, which
* may be a byte sequence or a stream.
*
* @author sunqian
*/
public interface ByteReader extends Closeable {
/**
* Wraps the given stream as a new {@link ByteReader}.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: based on the stream;</li>
* <li>close: closes the stream;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given stream
* @return the given stream as a new {@link ByteReader}
*/
static @Nonnull ByteReader from(@Nonnull InputStream src) {
return from(src, IOKit.bufferSize());
}
/**
* Wraps the given stream as a new {@link ByteReader} with the given buffer size.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: based on the stream;</li>
* <li>close: closes the stream;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given stream
* @param bufSize the given buffer size, must {@code > 0}
* @return the given stream as a new {@link ByteReader}
* @throws IllegalArgumentException if the given buffer size {@code <= 0}
*/
static @Nonnull ByteReader from(@Nonnull InputStream src, int bufSize) throws IllegalArgumentException {
return ByteReaderBack.of(src, bufSize);
}
/**
* Wraps the given channel as a new {@link ByteReader}.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: unsupported;</li>
* <li>close: closes the channel;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given channel
* @return the given channel as a new {@link ByteReader}
*/
static @Nonnull ByteReader from(@Nonnull ReadableByteChannel src) {
return from(src, IOKit.bufferSize());
}
/**
* Wraps the given channel as a new {@link ByteReader} with the given buffer size.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: unsupported;</li>
* <li>close: closes the channel;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given channel
* @param bufSize the given buffer size, must {@code > 0}
* @return the given channel as a new {@link ByteReader}
* @throws IllegalArgumentException if the given buffer size {@code <= 0}
*/
static @Nonnull ByteReader from(@Nonnull ReadableByteChannel src, int bufSize) throws IllegalArgumentException {
return ByteReaderBack.of(src, bufSize);
}
/**
* Wraps the given array as a new {@link ByteReader}.
* <p>
* The content of the segment returned from the {@link ByteReader#read(int)} is shared with the array. Any changes
* to the segment's content will be reflected in the array, and vice versa.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: supported;</li>
* <li>close: invoking has no effect;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given array
* @return the given array as a new {@link ByteReader}
*/
static @Nonnull ByteReader from(byte @Nonnull [] src) {
return from(src, 0, src.length);
}
/**
* Wraps a specified length of data from the given array, starting at the specified offset, as a new
* {@link ByteReader}.
* <p>
* The content of the segment returned from the {@link ByteReader#read(int)} is shared with the array. Any changes
* to the segment's content will be reflected in the array, and vice versa.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: supported;</li>
* <li>close: invoking has no effect;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given array
* @param off the specified offset
* @param len the specified length
* @return the given array as a new {@link ByteReader}
* @throws IndexOutOfBoundsException if the bounds arguments are out of bounds
*/
static @Nonnull ByteReader from(byte @Nonnull [] src, int off, int len) throws IndexOutOfBoundsException {
return ByteReaderBack.of(src, off, len);
}
/**
* Wraps the given buffer as a new {@link ByteReader}.
* <p>
* The content of the segment returned from the {@link ByteReader#read(int)} is shared with the array. Any changes
* to the segment's content will be reflected in the array (if it is not readonly), and vice versa.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: supported;</li>
* <li>close: invoking has no effect;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param src the given buffer
* @return the given buffer as a new {@link ByteReader}
*/
static @Nonnull ByteReader from(@Nonnull ByteBuffer src) {
return ByteReaderBack.of(src);
}
/**
* Returns the bytes number this reader is ready to be read, may be {@code 0}.
* <p>
* Note some data sources are unpredictable, so even if this method returns {@code 0}, it does not necessarily mean
* that there is no data can be read out immediately
*
* @return the bytes number this reader is ready to be read, may be {@code 0}
* @throws IORuntimeException if an I/O error occurs
*/
int ready() throws IORuntimeException;
/**
* Reads and returns the next specified length of data segment. This method reads continuously until the read number
* reaches the specified length or reaches the end of this reader. It never returns {@code null}, but can return an
* empty segment.
* <p>
* If the specified length is {@code 0}, returns an empty segment immediately without reading.
* <p>
* The content of the returned segment may be shared with the data source, depends on the implementation, such as
* the instances obtained from the {@link #from(byte[])}, {@link #from(byte[], int, int)} and
* {@link #from(ByteBuffer)}.
* <p>
* Note this method may allocate the specified length of space, and the excessive length may cause out of memory.
*
* @param len the specified length to read, must {@code >= 0}
* @return the next data segment
* @throws IllegalArgumentException if the specified length {@code < 0}
* @throws IORuntimeException if an I/O error occurs
*/
@Nonnull
ByteSegment read(int len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads all data from this reader, and returns an array contains the data. This method reads continuously until
* reaches the end of this reader. It may return {@code null} if the reader has already reached the end of the
* source and no data read out.
* <p>
* The content of the returned segment may be shared with the data source, depends on the implementation, such as
* the instances obtained from the {@link #from(byte[])}, {@link #from(byte[], int, int)} and
* {@link #from(ByteBuffer)}.
*
* @return the all data as buffer
* @throws IORuntimeException if an I/O error occurs
*/
@Nullable
ByteBuffer read() throws IORuntimeException;
/**
* Skips the next specified length of data segment. This method skips continuously until the skipped number reaches
* the specified length or reaches the end of this reader.
* <p>
* If the specified length is {@code 0}, returns {@code 0} immediately without skipping.
*
* @param len the specified length to skip, must {@code >= 0}
* @return the actual skipped length
* @throws IllegalArgumentException if the specified length {@code < 0}
* @throws IORuntimeException if an I/O error occurs
*/
long skip(long len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads all data into the specified output stream, until reaches the end of this reader, returns the actual number
* of bytes read to.
* <p>
* If reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output stream
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
long readTo(@Nonnull OutputStream dst) throws IORuntimeException;
/**
* Reads a specified length of data into the specified output stream, until the read number reaches the specified
* length or reaches the end of this reader, returns the actual number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading; if reaches the end of this reader and no
* data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output stream
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IllegalArgumentException if the specified length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
long readTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads all data into the specified output channel, until reaches the end of this reader, returns the actual number
* of bytes read to.
* <p>
* If reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output channel
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
long readTo(@Nonnull WritableByteChannel dst) throws IORuntimeException;
/**
* Reads a specified length of data into the specified output channel, until the read number reaches the specified
* length or reaches the end of this reader, returns the actual number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading; if reaches the end of this reader and no
* data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output channel
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IllegalArgumentException if the specified length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
long readTo(@Nonnull WritableByteChannel dst, long len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads data from this reader into the destination array, until the read number reaches the array's length or
* reaches the end of this reader, and returns the actual number of bytes read to.
* <p>
* If the array's length is {@code 0}, returns {@code 0} without reading. If reaches the end of this reader and no
* data is read, returns {@code -1}.
*
* @param dst the destination array
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
int readTo(byte @Nonnull [] dst) throws IORuntimeException;
/**
* Reads a specified length of data from this reader into the destination array, starting at the specified offset,
* until the read number reaches the specified length or reaches the end of this reader, and returns the actual
* number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading. If reaches the end of this reader and no
* data is read, returns {@code -1}.
*
* @param dst the destination array
* @param off the specified offset of the array
* @param len the specified length to read
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IndexOutOfBoundsException if the arguments are out of bounds
* @throws IORuntimeException if an I/O error occurs
*/
int readTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException, IORuntimeException;
/**
* Reads data from this reader into the destination buffer, until reaches the end of the reader or buffer, and
* returns the actual number of bytes read to.
* <p>
* If the destination buffer's remaining is {@code 0}, returns {@code 0} without reading; if reaches the end of this
* reader and no data is read, returns {@code -1}.
* <p>
* The buffer's position increments by the actual read number.
*
* @param dst the destination buffer
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
int readTo(@Nonnull ByteBuffer dst) throws IORuntimeException;
/**
* Reads a specified length of data from this reader into the destination buffer, until the read number reaches the
* specified length or reaches the end of the reader or buffer, and returns the actual number of bytes read to.
* <p>
* If the specified length or destination buffer's remaining is {@code 0}, returns {@code 0} without reading; if
* reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* The buffer's position increments by the actual read number.
*
* @param dst the specified buffer
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, or {@code -1} if reaches the end of this reader and no data is read
* @throws IllegalArgumentException if the specified read length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
int readTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads and returns the next specified length of data segment. This method reads continuously until the read number
* reaches the specified length or no data is immediately available. It never returns {@code null}, but can return
* an empty segment.
* <p>
* If the specified length is {@code 0}, returns an empty segment immediately without reading.
* <p>
* The content of the returned segment may be shared with the data source, depends on the implementation, such as
* the instances obtained from the {@link #from(byte[])}, {@link #from(byte[], int, int)} and
* {@link #from(ByteBuffer)}.
* <p>
* Note this method may allocate the specified length of space, and the excessive length may cause out of memory.
*
* @param len the specified length to read, must {@code >= 0}
* @return the next data segment
* @throws IllegalArgumentException if the specified length {@code < 0}
* @throws IORuntimeException if an I/O error occurs
*/
@Nonnull
ByteSegment available(int len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads and returns the next available data segment. This method reads continuously until no data is immediately
* available. It never returns {@code null}, but can return an empty segment.
* <p>
* The content of the returned segment may be shared with the data source, depends on the implementation, such as
* the instances obtained from the {@link #from(byte[])}, {@link #from(byte[], int, int)} and
* {@link #from(ByteBuffer)}.
*
* @return the next available data segment
* @throws IORuntimeException if an I/O error occurs
*/
@Nonnull
ByteSegment available() throws IORuntimeException;
/**
* Reads available data into the specified output stream, until no data is immediately available, returns the actual
* number of bytes read to.
* <p>
* If reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output stream
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
long availableTo(@Nonnull OutputStream dst) throws IORuntimeException;
/**
* Reads a specified length of data into the specified output stream, until the read number reaches the specified
* length or no data is immediately available, returns the actual number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading; if reaches the end of this reader and no
* data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output stream
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IllegalArgumentException if the specified length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
long availableTo(@Nonnull OutputStream dst, long len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads available data into the specified output channel, until no data is immediately available, returns the
* actual number of bytes read to.
* <p>
* If reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output channel
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
long availableTo(@Nonnull WritableByteChannel dst) throws IORuntimeException;
/**
* Reads a specified length of data into the specified output channel, until the read number reaches the specified
* length or no data is immediately available, returns the actual number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading; if reaches the end of this reader and no
* data is read, returns {@code -1}.
* <p>
* This method never invokes the {@link OutputStream#flush()} to force the backing buffer.
*
* @param dst the specified output channel
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IllegalArgumentException if the specified length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
long availableTo(@Nonnull WritableByteChannel dst, long len) throws IllegalArgumentException, IORuntimeException;
/**
* Reads available data from this reader into the destination array, until the read number reaches the array's
* length or no data is immediately available, and returns the actual number of bytes read to.
* <p>
* If the array's length is {@code 0}, returns {@code 0} without reading. If reaches the end of this reader and no
* data is read, returns {@code -1}.
*
* @param dst the destination array
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
int availableTo(byte @Nonnull [] dst) throws IORuntimeException;
/**
* Reads a specified length of data from this reader into the destination array, starting at the specified offset,
* until the read number reaches the specified length or no data is immediately available, and returns the actual
* number of bytes read to.
* <p>
* If the specified length is {@code 0}, returns {@code 0} without reading. If reaches the end of this reader and no
* data is read, returns {@code -1}.
*
* @param dst the destination array
* @param off the specified offset of the array
* @param len the specified length to read
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IndexOutOfBoundsException if the arguments are out of bounds
* @throws IORuntimeException if an I/O error occurs
*/
int availableTo(byte @Nonnull [] dst, int off, int len) throws IndexOutOfBoundsException, IORuntimeException;
/**
* Reads available data from this reader into the destination buffer, until reaches the end of the buffer or no data
* is immediately available, and returns the actual number of bytes read to.
* <p>
* If the destination buffer's remaining is {@code 0}, returns {@code 0} without reading; if reaches the end of this
* reader and no data is read, returns {@code -1}.
* <p>
* The buffer's position increments by the actual read number.
*
* @param dst the destination buffer
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IORuntimeException if an I/O error occurs
*/
int availableTo(@Nonnull ByteBuffer dst) throws IORuntimeException;
/**
* Reads a specified length of data from this reader into the destination buffer, until the read number reaches the
* specified length or reaches the end of the buffer or no data is immediately available, and returns the actual
* number of bytes read to.
* <p>
* If the specified length or destination buffer's remaining is {@code 0}, returns {@code 0} without reading; if
* reaches the end of this reader and no data is read, returns {@code -1}.
* <p>
* The buffer's position increments by the actual read number.
*
* @param dst the specified buffer
* @param len the specified length, must {@code >= 0}
* @return the actual number of bytes read to, possibly {@code 0}, or {@code -1} if reaches the end of this reader
* and no data is read
* @throws IllegalArgumentException if the specified read length is illegal
* @throws IORuntimeException if an I/O error occurs
*/
int availableTo(@Nonnull ByteBuffer dst, int len) throws IllegalArgumentException, IORuntimeException;
/**
* Returns whether this reader supports the {@link #mark()} and {@link #reset()} methods.
*
* @return whether this reader supports the {@link #mark()} and {@link #reset()} methods
*/
boolean markSupported();
/**
* Marks the current position in this reader. This method can be used to mark a position for later
* {@link #reset()}.
*
* @throws IORuntimeException if an I/O error occurs
*/
void mark() throws IORuntimeException;
/**
* Resets this reader to the last marked position by {@link #mark()}. This method can be used to re-read the data
* from last marked position.
*
* @throws IORuntimeException if an I/O error occurs
*/
void reset() throws IORuntimeException;
/**
* Closes this reader and the data source if the data source is closable. If this reader is already closed, this
* method has no effect.
*
* @throws IORuntimeException if an I/O error occurs
*/
@Override
void close() throws IORuntimeException;
/**
* Wraps this reader as a new {@link ByteReader} of which readable number is limited to the specified limit. The
* shareability of the content of the returned segment inherits this reader.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: based on this reader;</li>
* <li>close: closes this reader;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @param limit the specified limit, must {@code >= 0}
* @return this reader as a new {@link ByteReader} of which readable number is limited to the specified limit
* @throws IllegalArgumentException if the limit argument is negative
*/
default @Nonnull ByteReader limit(long limit) throws IllegalArgumentException {
return ByteReaderBack.limit(this, limit);
}
/**
* Returns an {@link InputStream} represents this reader. Its content and status are shared with this reader.
* <p>
* The result's support is as follows:
* <ul>
* <li>mark/reset: based on this reader;</li>
* <li>close: closes this reader;</li>
* <li>thread safety: no;</li>
* </ul>
*
* @return an {@link InputStream} represents this reader. Its content and status are shared with this reader
*/
default @Nonnull InputStream asInputStream() {
return ByteReaderBack.asInputStream(this);
}
}