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 + -
显示快捷键?