readstream.java
来自「RESIN 3.2 最新源码」· Java 代码 · 共 1,347 行 · 第 1/2 页
JAVA
1,347 行
/* * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */package com.caucho.vfs;import com.caucho.util.Alarm;import com.caucho.util.CharBuffer;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.Reader;import java.io.UnsupportedEncodingException;import java.io.Writer;import java.util.Iterator;import java.util.logging.Level;import java.util.logging.Logger;/** * A fast bufferered input stream supporting both character * and byte data. The underlying stream sources are provided by StreamImpl * classes, so all streams have the same API regardless of the underlying * implementation. * * <p>Dynamic streams, like tcp and http * will properly flush writes before reading input. And random access * streams, like RandomAccessFile, can use the same API as normal streams. * * <p>Most applications will use the Path routines to create their own streams. * Specialized applications, like servers, need the capability of recycling * streams. */public final class ReadStream extends InputStream implements LockableStream{ public static int ZERO_COPY_SIZE = 1024; private TempBuffer _tempRead; private byte []_readBuffer; private int _readOffset; private int _readLength; private WriteStream _sibling; private StreamImpl _source; private long _position; private long _readTime; private Reader _readEncoding; private String _readEncodingName; private int _specialEncoding; private boolean _disableClose; private boolean _isDisableCloseSource; private boolean _reuseBuffer; private Reader _reader; /** * Creates an uninitialized stream. Use <code>init</code> to initialize. */ public ReadStream() { } /** * Creates a stream and initializes with a specified source. * * @param source Underlying source for the stream. */ public ReadStream(StreamImpl source) { init(source, null); } /** * Creates a stream and initializes with a specified source. * * @param source Underlying source for the stream. * @param sibling Sibling write stream. */ public ReadStream(StreamImpl source, WriteStream sibling) { init(source, sibling); } /** * Initializes the stream with a given source. * * @param source Underlying source for the stream. * @param sibling Sibling write stream */ public void init(StreamImpl source, WriteStream sibling) { _disableClose = false; _isDisableCloseSource = false; _readTime = 0; if (_source != null && _source != source) { close(); } if (source == null) throw new IllegalArgumentException(); _source = source; _sibling = sibling; if (source.canRead()) { if (_tempRead == null) { _tempRead = TempBuffer.allocate(); _readBuffer = _tempRead._buf; } } _readOffset = 0; _readLength = 0; _readEncoding = null; _readEncodingName = "ISO-8859-1"; } public void setSibling(WriteStream sibling) { _sibling = sibling; } public WriteStream getSibling() { return _sibling; } /** * Returns the underlying source for the stream. * * @return the source */ public StreamImpl getSource() { return _source; } public void setReuseBuffer(boolean reuse) { _reuseBuffer = reuse; } /** * Pushes a filter on the top of the stream stack. * * @param filter the filter to be added. */ public void pushFilter(StreamFilter filter) { filter.init(_source); _source = filter; } public byte []getBuffer() { return _readBuffer; } public int getOffset() { return _readOffset; } public int getLength() { return _readLength; } public void setOffset(int offset) { _readOffset = offset; } /** * Returns the read position. */ public long getPosition() { return _position - (_readLength - _readOffset); } /** * Returns the last read-time. */ public long getReadTime() { return _readTime; } /** * Sets the current read position. */ public boolean setPosition(long pos) throws IOException { // Allow seeks to be reflected in the char Reader. if (_readEncoding != null) _readEncoding = Encoding.getReadEncoding(this, _readEncodingName); if (pos < 0) { // Return error on seek to negative stream position return false; } else if (pos < getPosition()) { // Seek backwards in the stream _position = pos; _readLength = _readOffset = 0; if (_source != null) { _source.seekStart(pos); return true; } else return false; } else { // Seek forward in the stream, skip any buffered bytes long n = pos - getPosition(); return skip(n) == n; } } /** * Clears the position for statistics cases like a socket stream. */ public void clearPosition() { _position = (_readLength - _readOffset); } /** * Returns true if the stream allows reading. */ public boolean canRead() { return _source.canRead(); } /** * Clears the read buffer. */ public void clearRead() { _readOffset = 0; _readLength = 0; } /** * Returns an estimate of the available bytes. If a read would not block, * it will always return greater than 0. */ public int getAvailable() throws IOException { if (_readOffset < _readLength) { return _readLength - _readOffset; } if (_sibling != null) _sibling.flush(); return _source.getAvailable(); } /** * Returns true if data in the buffer is available. */ public int getBufferAvailable() throws IOException { return _readLength - _readOffset; } /** * Compatibility with InputStream. */ @Override public int available() throws IOException { return getAvailable(); } /** * Returns the next byte or -1 if at the end of file. */ public final int read() throws IOException { if (_readLength <= _readOffset) { if (! readBuffer()) return -1; } return _readBuffer[_readOffset++] & 0xff; } /** * Unreads the last byte. */ public final void unread() { if (_readOffset <= 0) throw new RuntimeException(); _readOffset--; } /** * Waits for data to be available. */ public final boolean waitForRead() throws IOException { if (_readLength <= _readOffset) { if (! readBuffer()) return false; } return true; } /** * Skips the next <code>n</code> bytes. * * @param n bytes to skip. * * @return number of bytes skipped. */ @Override public long skip(long n) throws IOException { int buffered = _readLength - _readOffset; if (n < buffered) { _readOffset += n; return n; } _readLength = 0; _readOffset = 0; if (_source.hasSkip()) { if (_sibling != null) _sibling.flush(); long skipped = _source.skip(n - buffered); if (skipped < 0) return buffered; else { _position += skipped + buffered; return skipped + buffered; } } while (_readLength < (_readOffset + n - buffered)) { buffered += getBufferAvailable(); _readOffset = 0; _readLength = 0; if (! readBuffer()) return buffered; } _readOffset += (int) (n - buffered); return n; } /** * Reads into a byte array. <code>read</code> may return less than * the maximum bytes even if more bytes are available to read. * * @param buf byte array * @param offset offset into the byte array to start reading * @param length maximum byte allowed to read. * * @return number of bytes read or -1 on end of file. */ @Override public final int read(byte []buf, int offset, int length) throws IOException { int readOffset = _readOffset; int readLength = _readLength; if (readLength <= readOffset) { if (ZERO_COPY_SIZE <= length) { if (_sibling != null) _sibling.flush(); int len = _source.read(buf, offset, length); if (len > 0) { _position += len; _readTime = Alarm.getCurrentTime(); } return len; } if (! readBuffer()) return -1; readOffset = _readOffset; readLength = _readLength; } int sublen = readLength - readOffset; if (length < sublen) sublen = length; System.arraycopy(_readBuffer, readOffset, buf, offset, sublen); _readOffset = readOffset + sublen; return sublen; } /** * Reads into a byte array. <code>readAll</code> will always read * <code>length</code> bytes, blocking if necessary, until the end of * file is reached. * * @param buf byte array * @param offset offset into the byte array to start reading * @param length maximum byte allowed to read. * * @return number of bytes read or -1 on end of file. */ public int readAll(byte []buf, int offset, int length) throws IOException { int readLength = 0; while (length > 0) { int sublen = read(buf, offset, length); if (sublen < 0) return readLength == 0 ? -1 : readLength; offset += sublen; readLength += sublen; length -= sublen; } return readLength == 0 ? -1 : readLength; } /* * Reader methods */ /** * Sets the current read encoding. The encoding can either be a * Java encoding name or a mime encoding. * * @param encoding name of the read encoding */ public void setEncoding(String encoding) throws UnsupportedEncodingException { String mimeName = Encoding.getMimeName(encoding); if (mimeName != null && mimeName.equals(_readEncodingName)) return; _readEncoding = Encoding.getReadEncoding(this, encoding); _readEncodingName = mimeName; } /** * Returns the mime-encoding currently read. */ public String getEncoding() { return _readEncodingName; } /** * Reads a character from the stream, returning -1 on end of file. */ public final int readChar() throws IOException { if (_readEncoding != null) { int ch = _readEncoding.read(); return ch; } if (_readLength <= _readOffset) { if (! readBuffer()) return -1; } return _readBuffer[_readOffset++] & 0xff; } /** * Reads into a character buffer from the stream. Like the byte * array version, read may return less characters even though more * characters are available. * * @param buf character buffer to fill * @param offset starting offset into the character buffer * @param length maximum number of characters to read * @return number of characters read or -1 on end of file. */ public final int read(char []buf, int offset, int length) throws IOException { if (_readEncoding != null) return _readEncoding.read(buf, offset, length); byte []readBuffer = _readBuffer; if (readBuffer == null) return -1; int readOffset = _readOffset; int readLength = _readLength; int sublen = readLength - readOffset; if (sublen <= 0) { if (! readBuffer()) { return -1; } readLength = _readLength; readOffset = _readOffset; sublen = readLength - readOffset; } if (length < sublen) sublen = length; for (int i = 0; i < sublen; i++) buf[offset + i] = (char) (readBuffer[readOffset + i] & 0xff); _readOffset = readOffset + sublen; return sublen; } /** * Reads into a character buffer from the stream. <code>length</code> * characters will always be read until the end of file is reached. * * @param buf character buffer to fill * @param offset starting offset into the character buffer * @param length maximum number of characters to read * @return number of characters read or -1 on end of file. */ public int readAll(char []buf, int offset, int length) throws IOException { int readLength = 0; while (length > 0) { int sublen = read(buf, offset, length); if (sublen <= 0) return readLength > 0 ? readLength : -1; offset += sublen; readLength += sublen; length -= sublen; } return readLength; } /** * Reads characters from the stream, appending to the character buffer. * * @param buf character buffer to fill * @param length maximum number of characters to read * @return number of characters read or -1 on end of file. */ public int read(CharBuffer buf, int length) throws IOException { int len = buf.getLength(); buf.setLength(len + length); int readLength = read(buf.getBuffer(), len, length); if (readLength < 0) buf.setLength(len); else if (readLength < length) buf.setLength(len + readLength); return length; } /** * Reads characters from the stream, appending to the character buffer. * <code>length</code> characters will always be read until the end of * file. * * @param buf character buffer to fill * @param length maximum number of characters to read * @return number of characters read or -1 on end of file. */ public int readAll(CharBuffer buf, int length) throws IOException { int len = buf.getLength(); buf.setLength(len + length); int readLength = readAll(buf.getBuffer(), len, length); if (readLength < 0) buf.setLength(len); else if (readLength < length) buf.setLength(len + readLength); return length; } /** * Reads a line from the stream, returning a string. */ public final String readln() throws IOException { return readLine(); } /** * Reads a line, returning a string. */ public String readLine() throws IOException { CharBuffer cb = new CharBuffer(); if (readLine(cb, true)) return cb.toString(); else if (cb.length() == 0) return null; else return cb.toString(); } /** * Reads a line, returning a string. */ public String readLineNoChop() throws IOException { CharBuffer cb = new CharBuffer(); if (readLine(cb, false)) return cb.toString();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?