📄 rewindableinputstream.java
字号:
}
fData[fLength++] = (byte) b;
fOffset++;
return b & 0xff;
} // END read()
/**
* Reads up to len bytes of data from the input stream into an array of
* bytes. In its current implementation it cannot return more bytes than
* left in the buffer if in "non-chunked" mode
* (<code>fMayReadChunks == false</code>). After reaching the end of
* the buffer, each invocation of this method will read exactly 1 byte
* then. In "chunked" mode this method <em>may</em> return more than 1
* byte, but it doesn't buffer the result.
*
* <p>From the other hand, for the task of reading xml declaration, such
* behavior may be desirable, as we probably don't need reset/rewind
* functionality after we finished with charset deduction. It is good
* idea to call <code>enableChunkedMode</code> after that, in order to
* improve perfomance and lessen memoery consumption when reading the rest
* of the data.
*
* @return Total number of bytes actually read or <code>-1</code> if end
* of stream has been reached.
*
* @throws IOException when an I/O error occurs while reading data
*
* @throws IndexOutOfBoundsException in case of invalid <code>off</code>,
* <code>len</code> and <code>b.length</code> combination
*/
public int read(byte[] b, int off, int len) throws IOException {
if (null == b) {
throw new NullPointerException("Destination byte array is null.");
} else if (0 == len) {
return 0;
} else if ((b.length < off) || (b.length < (off + len)) || (0 > off) || (0 > len)) {
throw new IndexOutOfBoundsException();
}
int bytesLeft = fLength - fOffset;
/*
* There is no more bytes in the buffer. We either reading 1 byte
* from underlying InputStream and saving it in the buffer, or
* getting more bytes without saving them, depending on the value
* of `fMayReadChunks` field.
*/
if (bytesLeft == 0) {
if (fOffset == fEndOffset) {
return -1;
}
// better get some more for the voracious reader...
if (fMayReadChunks) {
// Hmm, this can be buffered in theory. But in many
// cases this would be undesirable, so let it be as it is.
return fInputStream.read(b, off, len);
}
int returnedVal = read();
if (returnedVal == -1) {
fEndOffset = fOffset;
return -1;
}
b[off] = (byte) returnedVal;
return 1;
}
/*
* In non-chunked mode we shouldn't give out more bytes then left
* in the buffer.
*/
if (fMayReadChunks) {
// Count of bytes to get form buffer
int readFromBuffer = (len < bytesLeft) ? len : bytesLeft;
System.arraycopy(fData, fOffset, b, off, readFromBuffer);
int readFromStream = 0;
if (len > bytesLeft) {
readFromStream = fInputStream.read(b, off + bytesLeft, len - bytesLeft);
}
fOffset += readFromBuffer;
return readFromBuffer + ((-1 == readFromStream) ? 0 : readFromStream);
} else {
//
// This will prevent returning more bytes than the remainder of
// the buffer array.
if (len > bytesLeft) {
len = bytesLeft;
}
System.arraycopy(fData, fOffset, b, off, len);
fOffset += len;
return len;
}
} // END read(byte[], int, int)
/**
* Skips over and discards <code>n</code> bytes of data from this input
* stream. The skip method may, for a variety of reasons, end up skipping
* over some smaller number of bytes, possibly <code>0</code>. The actual
* number of bytes skipped is returned. If <code>n</code> is negative, no
* bytes are skipped.
*
* @param n Number of bytes to be skipped.
*
* @return Number of bytes actually skipped.
*
* @throws IOException if an I/O error occurs.
*/
public long skip(long n) throws IOException {
int bytesLeft;
if (n <= 0) {
return 0;
}
bytesLeft = fLength - fOffset;
// If end of buffer is reached, using `skip()` of the underlying input
// stream
if (bytesLeft == 0) {
if (fOffset == fEndOffset) {
return 0;
}
return fInputStream.skip(n);
}
// Quickly "skipping" bytes in the buffer by modifying its pointer.
if (n <= bytesLeft) {
fOffset += n;
return n;
}
fOffset += bytesLeft;
if (fOffset == fEndOffset) {
return bytesLeft;
}
n -= bytesLeft;
return fInputStream.skip(n) + bytesLeft;
} // END skip(long)
/**
* Returns the number of bytes that can be read (or skipped over) from this
* input stream without blocking by the next caller of a method for this
* input stream. For <code>RewindableInputStream</code> this can be:
*
* <ul>
* <li>
* Number of unread bytes in the <code>fData</code> buffer, i.e. those
* between current position (fOffset) and total bytes quantity in the
* buffer (fLength).
* </li>
* <li>
* Result of underlying InputStream's <code>available</code> call
* if there are no unread bytes in the buffer.
* </li>
* <li>
* <code>-1</code> if end of stream is reached.
* </li>
* </ul>
*
* @return the number of bytes that can be read from this input stream
* without blocking.
*
* @throws IOException when an I/O error occurs.
*/
public int available() throws IOException {
int bytesLeft = fLength - fOffset;
if (bytesLeft == 0) {
// Again, the same thing as in `read()`. Do we need to throw
// an exception if fOffset > fEndOffset???
if (fOffset == fEndOffset) {
return -1;
}
/*
* In a manner of speaking, when this class isn't permitting more
* than one byte at a time to be read, it is "blocking". The
* available() method should indicate how much can be read without
* blocking, so while we're in this mode, it should only indicate
* that bytes in its buffer are available; otherwise, the result of
* available() on the underlying InputStream is appropriate.
*/
return fMayReadChunks ? fInputStream.available() : 0;
}
return bytesLeft;
}
/**
* Sets a mark to the current position in the stream.
*
* @param howMuch Not used in this implementation I guess.
*/
public void mark(int howMuch) {
fMark = fOffset;
}
/**
* Returns stream pointer to the position previously remembered
* using <code>mark</code> method (or to beginning of the stream,
* if there were no <code>mark</code> method calls).
*/
public void reset() {
fOffset = fMark;
}
/**
* Tells that this stream supports mark/reset capability.
* This one definitely supports it :)
*
* @return <code>true</code> if this stream instance supports the mark
* and reset methods; <code>false</code> otherwise.
*/
public boolean markSupported() {
return true;
}
/**
* Closes underlying byte stream.
*
* @throws IOException if an I/O error occurs.
*/
public void close() throws IOException {
if (fInputStream != null) {
fInputStream.close();
fInputStream = null;
fData = null;
}
}
} // end of RewindableInputStream class
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -