Java/File Input Output/InputStream

Материал из Java эксперт
Версия от 18:01, 31 мая 2010; (обсуждение)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

An input stream which reads sequentially from multiple sources

  
/*
 * Copyright (C) 2004 Stephen Ostermiller
 * http://ostermiller.org/contact.pl?regarding=Java+Utilities
 *
 * This program 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.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * See COPYING.TXT for details.
 */
import java.io.*;
import java.util.ArrayList;
/**
 * An input stream which reads sequentially from multiple sources.
 * More information about this class is available from .
 *
 * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
 * @since ostermillerutils 1.04.00
 */
public class ConcatInputStream extends InputStream {

  /**
   * Current index to inputStreamQueue
   *
   * @since ostermillerutils 1.04.01
   */
  private int inputStreamQueueIndex = 0;
  /**
   * Queue of inputStreams that have yet to be read from.
   *
   * @since ostermillerutils 1.04.01
   */
  private ArrayList<InputStream> inputStreamQueue = new ArrayList<InputStream>();
  /**
   * A cache of the current inputStream from the inputStreamQueue
   * to avoid unneeded access to the queue which must
   * be synchronized.
   *
   * @since ostermillerutils 1.04.01
   */
  private InputStream currentInputStream = null;
  /**
   * true iff the client may add more inputStreams.
   *
   * @since ostermillerutils 1.04.01
   */
  private boolean doneAddingInputStreams = false;
  /**
   * Causes the addInputStream method to throw IllegalStateException
   * and read() methods to return -1 (end of stream)
   * when there is no more available data.
   * <p>
   * Calling this method when this class is no longer accepting
   * more inputStreams has no effect.
   *
   * @since ostermillerutils 1.04.01
   */
  public void lastInputStreamAdded(){
    doneAddingInputStreams = true;
  }
  /**
   * Add the given inputStream to the queue of inputStreams from which to
   * concatenate data.
   *
   * @param in InputStream to add to the concatenation.
   * @throws IllegalStateException if more inputStreams can"t be added because lastInputStreamAdded() has been called, close() has been called, or a constructor with inputStream parameters was used.
   *
   * @since ostermillerutils 1.04.01
   */
  public void addInputStream(InputStream in){
    synchronized(inputStreamQueue){
      if (in == null) throw new NullPointerException();
      if (closed) throw new IllegalStateException("ConcatInputStream has been closed");
      if (doneAddingInputStreams) throw new IllegalStateException("Cannot add more inputStreams - the last inputStream has already been added.");
      inputStreamQueue.add(in);
    }
  }
  /**
   * Add the given inputStream to the queue of inputStreams from which to
   * concatenate data.
   *
   * @param in InputStream to add to the concatenation.
   * @throws IllegalStateException if more inputStreams can"t be added because lastInputStreamAdded() has been called, close() has been called, or a constructor with inputStream parameters was used.
   * @throws NullPointerException the array of inputStreams, or any of the contents is null.
   *
   * @since ostermillerutils 1.04.01
   */
  public void addInputStreams(InputStream[] in){
    for (InputStream element: in) {
      addInputStream(element);
    }
  }
  /**
   * Gets the current inputStream, looking at the next
   * one in the list if the current one is null.
   *
   * @since ostermillerutils 1.04.01
   */
  private InputStream getCurrentInputStream(){
    if (currentInputStream == null && inputStreamQueueIndex < inputStreamQueue.size()){
      synchronized(inputStreamQueue){
        // inputStream queue index is advanced only by the nextInputStream()
        // method.  Don"t do it here.
        currentInputStream = inputStreamQueue.get(inputStreamQueueIndex);
      }
    }
    return currentInputStream;
  }
  /**
   * Indicate that we are done with the current inputStream and we should
   * advance to the next inputStream.
   *
   * @since ostermillerutils 1.04.01
   */
  private void advanceToNextInputStream(){
    currentInputStream = null;
    inputStreamQueueIndex++;
  }
  /**
   * True iff this the close() method has been called on this stream.
   *
   * @since ostermillerutils 1.04.00
   */
  private boolean closed = false;

  /**
   * Create a new input stream that can dynamically accept new sources.
   * <p>
   * New sources should be added using the addInputStream() method.
   * When all sources have been added the lastInputStreamAdded() should
   * be called so that read methods can return -1 (end of stream).
   * <p>
   * Adding new sources may by interleaved with read calls.
   *
   * @since ostermillerutils 1.04.01
   */
  public ConcatInputStream(){
    // Empty constructor
  }
  /**
   * Create a new InputStream with one source.
   *
   * @param in InputStream to use as a source.
   *
   * @throws NullPointerException if in is null
   *
   * @since ostermillerutils 1.04.00
   */
  public ConcatInputStream(InputStream in){
    addInputStream(in);
    lastInputStreamAdded();
  }
  /**
   * Create a new InputStream with two sources.
   *
   * @param in1 first InputStream to use as a source.
   * @param in2 second InputStream to use as a source.
   *
   * @throws NullPointerException if either source is null.
   *
   * @since ostermillerutils 1.04.00
   */
  public ConcatInputStream(InputStream in1, InputStream in2){
    addInputStream(in1);
    addInputStream(in2);
    lastInputStreamAdded();
  }
  /**
   * Create a new InputStream with an arbitrary number of sources.
   *
   * @param in InputStreams to use as a sources.
   *
   * @throws NullPointerException if the input array on any element is null.
   *
   * @since ostermillerutils 1.04.00
   */
  public ConcatInputStream(InputStream[] in){
    addInputStreams(in);
    lastInputStreamAdded();
  }
  /**
   * Reads the next byte of data from the underlying streams. The value byte is
   * returned as an int in the range 0 to 255. If no byte is available because
   * the end of the stream has been reached, the value -1 is returned. This method
   * blocks until input data is available, the end of the stream is detected, or
   * an exception is thrown.
   * <p>
   * If this class in not done accepting inputstreams and the end of the last known
   * stream is reached, this method will block forever unless another thread
   * adds an inputstream or interrupts.
   *
   * @return the next byte of data, or -1 if the end of the stream is reached.
   *
   * @throws IOException if an I/O error occurs.
   */
  @Override public int read() throws IOException {
    if (closed) throw new IOException("InputStream closed");
    int r = -1;
    while (r == -1){
      InputStream in = getCurrentInputStream();
      if (in == null){
        if (doneAddingInputStreams) return -1;
        try {
          Thread.sleep(100);
        } catch (InterruptedException iox){
          throw new IOException("Interrupted");
        }
      } else {
        r = in.read();
        if (r == -1) advanceToNextInputStream();
      }
    }
    return r;
  }
  /**
   * Reads some number of bytes from the underlying streams and stores them into
   * the buffer array b. The number of bytes actually read is returned as an
   * integer. This method blocks until input data is available, end of file is
   * detected, or an exception is thrown.
   * <p>
   * If the length of b is zero,
   * then no bytes are read and 0 is returned; otherwise, there is an attempt
   * to read at least one byte.
   * <p>
   * The read(b) method for class InputStream has the same effect as:<br>
   * read(b, 0, b.length)
   * <p>
   * If this class in not done accepting inputstreams and the end of the last known
   * stream is reached, this method will block forever unless another thread
   * adds an inputstream or interrupts.
   *
   * @param b - Destination buffer
   * @return The number of bytes read, or -1 if the end of the stream has been reached
   *
   * @throws IOException - If an I/O error occurs
   * @throws NullPointerException - If b is null.
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public int read(byte[] b) throws IOException {
    return read(b, 0, b.length);
  }
  /**
   * Reads up to length bytes of data from the underlying streams into an array of bytes.
   * An attempt is made to read as many as length bytes, but a smaller number may be read,
   * possibly zero. The number of bytes actually read is returned as an integer.
   * <p>
   * If length is zero,
   * then no bytes are read and 0 is returned; otherwise, there is an attempt
   * to read at least one byte.
   * <p>
   * This method blocks until input data is available
   * <p>
   * If this class in not done accepting inputstreams and the end of the last known
   * stream is reached, this method will block forever unless another thread
   * adds an inputstream or interrupts.
   *
   * @param b Destination buffer
   * @param off Offset at which to start storing bytes
   * @param len Maximum number of bytes to read
   * @return The number of bytes read, or -1 if the end of the stream has been reached
   *
   * @throws IOException - If an I/O error occurs
   * @throws NullPointerException - If b is null.
   * @throws IndexOutOfBoundsException - if length or offset are not possible.
   */
  @Override public int read(byte[] b, int off, int len) throws IOException {
    if (off < 0 || len < 0 || off + len > b.length) throw new IllegalArgumentException();
    if (closed) throw new IOException("InputStream closed");
    int r = -1;
    while (r == -1){
      InputStream in = getCurrentInputStream();
      if (in == null){
        if (doneAddingInputStreams) return -1;
        try {
          Thread.sleep(100);
        } catch (InterruptedException iox){
          throw new IOException("Interrupted");
        }
      } else {
        r = in.read(b, off, len);
        if (r == -1) advanceToNextInputStream();
      }
    }
    return r;
  }
  /**
   * Skips over and discards n 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 0. This may result from any of a number of conditions; reaching end of
   * file before n bytes have been skipped is only one possibility. The actual number
   * of bytes skipped is returned. If n is negative, no bytes are skipped.
   * <p>
   * If this class in not done accepting inputstreams and the end of the last known
   * stream is reached, this method will block forever unless another thread
   * adds an inputstream or interrupts.
   *
   * @param n he number of characters to skip
   * @return The number of characters actually skipped
   *
   * @throws IOException If an I/O error occurs
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public long skip(long n) throws IOException {
    if (closed) throw new IOException("InputStream closed");
    if (n <= 0) return 0;
    long s = -1;
    while (s <= 0){
      InputStream in = getCurrentInputStream();
      if (in == null){
        if (doneAddingInputStreams) return 0;
        try {
          Thread.sleep(100);
        } catch (InterruptedException iox){
          throw new IOException("Interrupted");
        }
      } else {
        s = in.skip(n);
        // When nothing was skipped it is a bit of a puzzle.
        // The most common cause is that the end of the underlying
        // stream was reached.  In which case calling skip on it
        // will always return zero.  If somebody were calling skip
        // until it skipped everything they needed, there would
        // be an infinite loop if we were to return zero here.
        // If we get zero, let us try to read one character so
        // we can see if we are at the end of the stream.  If so,
        // we will move to the next.
        if (s <= 0) {
          // read() will advance to the next stream for us, so don"t do it again
          s = ((read()==-1)?-1:1);
        }
      }
    }
    return s;
  }
  /**
   * 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.
   * The next caller might be the same thread or or another thread.
   *
   * @throws IOException If an I/O error occurs
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public int available() throws IOException {
    if (closed) throw new IOException("InputStream closed");
    InputStream in = getCurrentInputStream();
    if (in == null) return 0;
    return in.available();
  }
  /**
   * Closes this input stream and releases any system resources associated with the stream.
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public void close() throws IOException {
    if (closed) return;
    for (Object element: inputStreamQueue) {
      ((InputStream)element).close();
    }
    closed = true;
  }
  /**
   * Mark not supported
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public void mark(int readlimit){
    // Mark not supported -- do nothing
  }
  /**
   * Reset not supported.
   *
   * @throws IOException because reset is not supported.
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public void reset() throws IOException {
    throw new IOException("Reset not supported");
  }
  /**
   * Does not support mark.
   *
   * @return false
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public boolean markSupported(){
    return false;
  }
}





An limited-data-size input stream

     
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * An input stream, which limits its data size. This stream is
 * used, if the content length is unknown.
 */
public abstract class LimitedInputStream
        extends FilterInputStream {
    /**
     * The maximum size of an item, in bytes.
     */
    private long sizeMax;
    /**
     * The current number of bytes.
     */
    private long count;
    /**
     * Whether this stream is already closed.
     */
    private boolean closed;
    /**
     * Creates a new instance.
     * @param pIn The input stream, which shall be limited.
     * @param pSizeMax The limit; no more than this number of bytes
     *   shall be returned by the source stream.
     */
    public LimitedInputStream(InputStream pIn, long pSizeMax) {
        super(pIn);
        sizeMax = pSizeMax;
    }
    /**
     * Called to indicate, that the input streams limit has
     * been exceeded.
     * @param pSizeMax The input streams limit, in bytes.
     * @param pCount The actual number of bytes.
     * @throws IOException The called method is expected
     *   to raise an IOException.
     */
    protected abstract void raiseError(long pSizeMax, long pCount)
            throws IOException;
    /** Called to check, whether the input streams
     * limit is reached.
     * @throws IOException The given limit is exceeded.
     */
    private void checkLimit() throws IOException {
        if (count > sizeMax) {
            raiseError(sizeMax, count);
        }
    }
    /**
     * Reads the next byte of data from this input stream. The value
     * byte is returned as an <code>int</code> in the range
     * <code>0</code> to <code>255</code>. If no byte is available
     * because the end of the stream has been reached, the value
     * <code>-1</code> is returned. This method blocks until input data
     * is available, the end of the stream is detected, or an exception
     * is thrown.
     * <p>
     * This method
     * simply performs <code>in.read()</code> and returns the result.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public int read() throws IOException {
        int res = super.read();
        if (res != -1) {
            count++;
            checkLimit();
        }
        return res;
    }
    /**
     * Reads up to <code>len</code> bytes of data from this input stream
     * into an array of bytes. If <code>len</code> is not zero, the method
     * blocks until some input is available; otherwise, no
     * bytes are read and <code>0</code> is returned.
     * <p>
     * This method simply performs <code>in.read(b, off, len)</code>
     * and returns the result.
     *
     * @param      b     the buffer into which the data is read.
     * @param      off   The start offset in the destination array
     *                   <code>b</code>.
     * @param      len   the maximum number of bytes read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
     * <code>len</code> is negative, or <code>len</code> is greater than
     * <code>b.length - off</code>
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public int read(byte[] b, int off, int len) throws IOException {
        int res = super.read(b, off, len);
        if (res > 0) {
            count += res;
            checkLimit();
        }
        return res;
    }
    /**
     * Returns, whether this stream is already closed.
     * @return True, if the stream is closed, otherwise false.
     * @throws IOException An I/O error occurred.
     */
    public boolean isClosed() throws IOException {
        return closed;
    }
    /**
     * Closes this input stream and releases any system resources
     * associated with the stream.
     * This
     * method simply performs <code>in.close()</code>.
     *
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterInputStream#in
     */
    public void close() throws IOException {
        closed = true;
        super.close();
    }
}





A trace of the data that is being retrieved from an input stream

 
/*
 * The contents of this file are subject to the terms 
 * of the Common Development and Distribution License 
 * (the "License").  You may not use this file except 
 * in compliance with the License.
 * 
 * You can obtain a copy of the license at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt or 
 * https://glassfish.dev.java.net/public/CDDLv1.0.html. 
 * See the License for the specific language governing 
 * permissions and limitations under the License.
 * 
 * When distributing Covered Code, include this CDDL 
 * HEADER in each file and include the License file at 
 * glassfish/bootstrap/legal/CDDLv1.0.txt.  If applicable, 
 * add the following below this CDDL HEADER, with the 
 * fields enclosed by brackets "[]" replaced with your 
 * own identifying information: Portions Copyright [yyyy] 
 * [name of copyright owner]
 */
/*
 * @(#)TraceInputStream.java  1.7 05/08/29
 *
 * Copyright 1997-2005 Sun Microsystems, Inc. All Rights Reserved.
 */
//Revised from sun mail util
import java.io.*;
/**
 * This class is a FilterInputStream that writes the bytes
 * being read from the given input stream into the given output
 * stream. This class is typically used to provide a trace of
 * the data that is being retrieved from an input stream.
 *
 * @author John Mani
 */
public class TraceInputStream extends FilterInputStream {
    private boolean trace = false;
    private boolean quote = false;
    private OutputStream traceOut;
    /**
     * Creates an input stream filter built on top of the specified
     * input stream.
     *   
     * @param   in   the underlying input stream.
     * @param   out  the trace stream
     */
    public TraceInputStream(InputStream in, OutputStream traceOut) {
  super(in);
  this.traceOut = traceOut;
    }
    /**
     * Set trace mode.
     * @param trace the trace mode
     */
    public void setTrace(boolean trace) {
  this.trace = trace;
    }
    /**
     * Set quote mode.
     * @param quote the quote mode
     */
    public void setQuote(boolean quote) {
  this.quote = quote;
    }
    /**
     * Reads the next byte of data from this input stream. Returns
     * <code>-1</code> if no data is available. Writes out the read
     * byte into the trace stream, if trace mode is <code>true</code>
     */
    public int read() throws IOException {
  int b = in.read();
  if (trace && b != -1) {
      if (quote)
    writeByte(b);
      else
    traceOut.write(b);
  }
  return b;
    }
    /**
     * Reads up to <code>len</code> bytes of data from this input stream
     * into an array of bytes. Returns <code>-1</code> if no more data
     * is available. Writes out the read bytes into the trace stream, if 
     * trace mode is <code>true</code>
     */
    public int read(byte b[], int off, int len) throws IOException {
  int count = in.read(b, off, len);
  if (trace && count != -1) {
      if (quote) {
    for (int i = 0; i < count; i++)
        writeByte(b[off + i]);
      } else
    traceOut.write(b, off, count);
  }
  return count;
    }
    /**
     * Write a byte in a way that every byte value is printable ASCII.
     */
    private final void writeByte(int b) throws IOException {
  b &= 0xff;
  if (b > 0x7f) {
      traceOut.write("M");
      traceOut.write("-");
      b &= 0x7f;
  }
  if (b == "\r") {
      traceOut.write("\\");
      traceOut.write("r");
  } else if (b == "\n") {
      traceOut.write("\\");
      traceOut.write("n");
      traceOut.write("\n");
  } else if (b == "\t") {
      traceOut.write("\\");
      traceOut.write("t");
  } else if (b < " ") {
      traceOut.write("^");
      traceOut.write("@" + b);
  } else {
      traceOut.write(b);
  }
    }
}





Combined InputStream

  
/**
 * Project pack:tag >> http://packtag.sf.net
 *
 * This software is published under the terms of the LGPL
 * License version 2.1, a copy of which has been included with this
 * distribution in the "lgpl.txt" file.
 * 
 * Creation date: 15.04.2007 - 18:27:26
 * Last author:   $Author: danielgalan $
 * Last modified: $Date: 2008/02/10 20:03:21 $
 * Revision:      $Revision: 1.4 $
 * 
 * $Log: CombinedInputStream.java,v $
 * Revision 1.4  2008/02/10 20:03:21  danielgalan
 * Fix for IE - if after a closing bracket a var keyword is, IE can"t interpret this, eg "varx={}var y ={}" mus be seperated: "varx={}\nvar y ={}"
 *
 * Revision 1.3  2007/05/02 21:38:38  danielgalan
 * alias to name
 *
 * Revision 1.2  2007/05/02 21:29:18  danielgalan
 * last fixes for 2.0, attribute media
 *
 * Revision 1.1  2007/04/22 19:04:24  danielgalan
 * pack.tag moved from subversion to good old CVS
 */
import java.io.IOException;
import java.io.InputStream;

/**
 * Reads multiple Inputstreams as one
 * 
 * @author  Daniel Gal&aacute;n y Martins
 * @version $Revision: 1.4 $
 */
public class CombinedInputStream extends InputStream {
  /** The current Stream to read from */
  private int current;
  boolean isNextLineFeed = false;
  /** The Streams to combine */
  private final InputStream[] streams;

  /**
   * Constructs an combined InputStream, that reads from array stream per stream, till the last stream
   * 
   * @param streams All Streams that will be combined
   */
  public CombinedInputStream(final InputStream[] streams) {
    current = 0;
    this.streams = streams;
  }

  /**
   * Reads from the list of streams, when the last stream is over, -1 will be returned (as usual)
   */
  public int read() throws IOException {
    if (isNextLineFeed) {
      isNextLineFeed = false;
      return "\n";
    }
    int i = -1;
    if (current < streams.length) {
      i = streams[current].read();
      if (i == -1) {
        isNextLineFeed = true;
        // the current stream has been finished, use the next one
        current++;
        return read();
      }
    }
    return i;
  }

  /** Closes all streams */
  public void close() throws IOException {
    for (int i = 0; i < streams.length; i++) {
      streams[i].close();
    }
  }

  /** Is there more data to read */
  public int available() throws IOException {
    return current < streams.length ? streams[current].available() : 0;
  }
}





Compare two InputStream

  
/*
 * JBoss DNA (http://www.jboss.org/dna)
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * See the AUTHORS.txt file in the distribution for a full listing of 
 * individual contributors. 
 *
 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
 * is licensed to you under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * JBoss DNA 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. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.Arrays;
/**
 * @author Randall Hauch
 */
public class Main {
  /**
   * Compare two input stream
   * 
   * @param input1 the first stream
   * @param input2 the second stream
   * @return true if the streams contain the same content, or false otherwise
   * @throws IOException
   * @throws IllegalArgumentException if the stream is null
   */
  public static boolean isSame( InputStream input1,
                                InputStream input2 ) throws IOException {
      boolean error = false;
      try {
          byte[] buffer1 = new byte[1024];
          byte[] buffer2 = new byte[1024];
          try {
              int numRead1 = 0;
              int numRead2 = 0;
              while (true) {
                  numRead1 = input1.read(buffer1);
                  numRead2 = input2.read(buffer2);
                  if (numRead1 > -1) {
                      if (numRead2 != numRead1) return false;
                      // Otherwise same number of bytes read
                      if (!Arrays.equals(buffer1, buffer2)) return false;
                      // Otherwise same bytes read, so continue ...
                  } else {
                      // Nothing more in stream 1 ...
                      return numRead2 < 0;
                  }
              }
          } finally {
              input1.close();
          }
      } catch (IOException e) {
          error = true; // this error should be thrown, even if there is an error closing stream 2
          throw e;
      } catch (RuntimeException e) {
          error = true; // this error should be thrown, even if there is an error closing stream 2
          throw e;
      } finally {
          try {
              input2.close();
          } catch (IOException e) {
              if (!error) throw e;
          }
      }
  }
}





Convert InputStream to String

    
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Main {
  public static void main(String[] args) throws Exception {
    InputStream is = Main.class.getResourceAsStream("/data.txt");
    System.out.println(convertStreamToString(is));
  }
  public static String convertStreamToString(InputStream is) throws Exception {
    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
    StringBuilder sb = new StringBuilder();
    String line = null;
    while ((line = reader.readLine()) != null) {
      sb.append(line + "\n");
    }
    is.close();
    return sb.toString();
  }
}





Convert Reader to InputStream

 
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
import java.io.*;

/**
* This class convert Reader to InputStream. It works by converting
* the characters to the encoding specified in constructor parameter.
*
* @author   Petr Hamernik, David Strupl
*/
public class ReaderInputStream extends InputStream {
    /** Input Reader class. */
    private Reader reader;
    private PipedOutputStream pos;
    private PipedInputStream pis;
    private OutputStreamWriter osw;
    /** Creates new input stream from the given reader.
     * Uses the platform default encoding.
    * @param reader Input reader
    */
    public ReaderInputStream(Reader reader) throws IOException {
        this.reader = reader;
        pos = new PipedOutputStream();
        pis = new PipedInputStream(pos);
        osw = new OutputStreamWriter(pos);
    }
    /** Creates new input stream from the given reader and encoding.
     * @param reader Input reader
     * @param encoding
     */
    public ReaderInputStream(Reader reader, String encoding)
    throws IOException {
        this.reader = reader;
        pos = new PipedOutputStream();
        pis = new PipedInputStream(pos);
        osw = new OutputStreamWriter(pos, encoding);
    }
    public int read() throws IOException {
        if (pis.available() > 0) {
            return pis.read();
        }
        int c = reader.read();
        if (c == -1) {
            return c;
        }
        osw.write(c);
        osw.flush();
        pos.flush();
        return pis.read();
    }
    public int read(byte[] b, int off, int len) throws IOException {
        if (len == 0) {
            return 0;
        }
        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte) c;
        int i = 1;
        // Don"t try to fill up the buffer if the reader is waiting.
        for (; (i < len) && reader.ready(); i++) {
            c = read();
            if (c == -1) {
                return i;
            }
            b[off + i] = (byte) c;
        }
        return i;
    }
    public int available() throws IOException {
        int i = pis.available();
        if (i > 0) {
            return i;
        }
        if (reader.ready()) {
            // Char must produce at least one byte.
            return 1;
        } else {
            return 0;
        }
    }
    public void close() throws IOException {
        reader.close();
        osw.close();
        pis.close();
    }
}





Creating a Manifest for a JAR File

    
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.jar.Manifest;
public class Main {
  public static void main(String[] argv) throws Exception {
    // Create a manifest from a file
    InputStream fis = new FileInputStream("manifestfile");
    Manifest manifest = new Manifest(fis);
    // Construct a string version of a manifest
    StringBuffer sbuf = new StringBuffer();
    sbuf.append("Manifest-Version: 1.0\n");
    sbuf.append("\n");
    sbuf.append("Name: javax/swing/JScrollPane.class\n");
    sbuf.append("Java-Bean: True\n");
    // Convert the string to a input stream
    InputStream is = new ByteArrayInputStream(sbuf.toString().getBytes("UTF-8"));
    // Create the manifest
    manifest = new Manifest(is);
  }
}





Creating an input or output stream on a ByteBuffer

    
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
public class Main {
  public static void main(String[] argv) throws Exception {
    ByteBuffer buf = ByteBuffer.allocate(10);
    OutputStream os = new ByteBufferBackedOutputStream(buf);
    InputStream is = new  ByteBufferBackedInputStream(buf);
  }
}
class ByteBufferBackedInputStream extends InputStream{
  
  ByteBuffer buf;
  ByteBufferBackedInputStream( ByteBuffer buf){
    this.buf = buf;
  }
  public synchronized int read() throws IOException {
    if (!buf.hasRemaining()) {
      return -1;
    }
    return buf.get();
  }
  public synchronized int read(byte[] bytes, int off, int len) throws IOException {
    len = Math.min(len, buf.remaining());
    buf.get(bytes, off, len);
    return len;
  }
}
class ByteBufferBackedOutputStream extends OutputStream{
  ByteBuffer buf;
  ByteBufferBackedOutputStream( ByteBuffer buf){
    this.buf = buf;
  }
  public synchronized void write(int b) throws IOException {
    buf.put((byte) b);
  }
  public synchronized void write(byte[] bytes, int off, int len) throws IOException {
    buf.put(bytes, off, len);
  }
  
}





Deserializes an object from an input stream.

  
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class Main {
  /**
   * This method deserializes an object from an input stream.
   *
   * @param file The input file
   * @return The deserialized object
   * @exception IOException IOError
   */
  public static Object deserializeObject(File file)
  throws IOException, ClassNotFoundException {
      FileInputStream fis = new FileInputStream(file);
      Object object = null;
      try {
          ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
          object = ois.readObject();
      } finally {
          fis.close();
      }
      return object;
  }
}





EOLConvertingInputStream: InputStream which converts \r bytes not followed by \n and \n not preceded by \r to \r\n.

 
/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
/**
 * InputStream which converts <code>\r</code>
 * bytes not followed by <code>\n</code> and <code>\n</code> not 
 * preceded by <code>\r</code> to <code>\r\n</code>.
 */
public class EOLConvertingInputStream extends InputStream {
    /** Converts single "\r" to "\r\n" */
    public static final int CONVERT_CR   = 1;
    /** Converts single "\n" to "\r\n" */
    public static final int CONVERT_LF   = 2;
    /** Converts single "\r" and "\n" to "\r\n" */
    public static final int CONVERT_BOTH = 3;
    
    private PushbackInputStream in = null;
    private int previous = 0;
    private int flags = CONVERT_BOTH;
    
    /**
     * Creates a new <code>EOLConvertingInputStream</code>
     * instance converting bytes in the given <code>InputStream</code>.
     * The flag <code>CONVERT_BOTH</code> is the default.
     * 
     * @param in the <code>InputStream</code> to read from.
     */
    public EOLConvertingInputStream(InputStream in) {
        this(in, CONVERT_BOTH);
    }
    /**
     * Creates a new <code>EOLConvertingInputStream</code>
     * instance converting bytes in the given <code>InputStream</code>.
     * 
     * @param in the <code>InputStream</code> to read from.
     * @param flags one of <code>CONVERT_CR</code>, <code>CONVERT_LF</code> or
     *        <code>CONVERT_BOTH</code>.
     */
    public EOLConvertingInputStream(InputStream in, int flags) {
        super();
        
        this.in = new PushbackInputStream(in, 2);
        this.flags = flags;
    }
    /**
     * Closes the underlying stream.
     * 
     * @throws IOException on I/O errors.
     */
    @Override
    public void close() throws IOException {
        in.close();
    }
    
    /**
     * @see java.io.InputStream#read()
     */
    @Override
    public int read() throws IOException {
        int b = in.read();
        
        if (b == -1) {
            return -1;
        }
        
        if ((flags & CONVERT_CR) != 0 && b == "\r") {
            int c = in.read();
            if (c != -1) {
                in.unread(c);
            }
            if (c != "\n") {
                in.unread("\n");
            }
        } else if ((flags & CONVERT_LF) != 0 && b == "\n" && previous != "\r") {
            b = "\r";
            in.unread("\n");
        }
        
        previous = b;
        
        return b;
    }
}





Minimal InputStream subclass to fetch bytes form a String

  
/* Copyright (c) 2001-2009, The HSQL Development Group
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of the HSQL Development Group nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.IOException;
import java.io.InputStream;
/**
 * minimal InputStream subclass to fetch bytes form a String
 *
 * @author Fred Toussi (fredt@users dot sourceforge.net)
 * @version 1.7.0
 */
public class StringInputStream extends InputStream {
    protected int    strOffset  = 0;
    protected int    charOffset = 0;
    protected int    available;
    protected String str;
    public StringInputStream(String s) {
        str       = s;
        available = s.length() * 2;
    }
    public int read() throws java.io.IOException {
        if (available == 0) {
            return -1;
        }
        available--;
        char c = str.charAt(strOffset);
        if (charOffset == 0) {
            charOffset = 1;
            return (c & 0x0000ff00) >> 8;
        } else {
            charOffset = 0;
            strOffset++;
            return c & 0x000000ff;
        }
    }
    public int available() throws IOException {
        return available;
    }
}





Read and return the entire contents of the supplied InputStream.

  
/*
 * JBoss DNA (http://www.jboss.org/dna)
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * See the AUTHORS.txt file in the distribution for a full listing of 
 * individual contributors. 
 *
 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
 * is licensed to you under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * JBoss DNA 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. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
 * @author Randall Hauch
 */
public class Main {

  /**
   * Read and return the entire contents of the supplied {@link InputStream stream}. This method always closes the stream when
   * finished reading.
   * 
   * @param stream the stream to the contents; may be null
   * @return the contents, or an empty byte array if the supplied reader is null
   * @throws IOException if there is an error reading the content
   */
  public static byte[] readBytes( InputStream stream ) throws IOException {
      if (stream == null) return new byte[] {};
      byte[] buffer = new byte[1024];
      ByteArrayOutputStream output = new ByteArrayOutputStream();
      boolean error = false;
      try {
          int numRead = 0;
          while ((numRead = stream.read(buffer)) > -1) {
              output.write(buffer, 0, numRead);
          }
      } catch (IOException e) {
          error = true; // this error should be thrown, even if there is an error closing stream
          throw e;
      } catch (RuntimeException e) {
          error = true; // this error should be thrown, even if there is an error closing stream
          throw e;
      } finally {
          try {
              stream.close();
          } catch (IOException e) {
              if (!error) throw e;
          }
      }
      output.flush();
      return output.toByteArray();
  }
}





Read and return the entire contents of the supplied InputStream. This method always closes the stream when finished reading.

  
/*
 * JBoss DNA (http://www.jboss.org/dna)
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * See the AUTHORS.txt file in the distribution for a full listing of 
 * individual contributors. 
 *
 * JBoss DNA is free software. Unless otherwise indicated, all code in JBoss DNA
 * is licensed to you under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * JBoss DNA 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. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
/**
 * @author Randall Hauch
 */
public class Main {
  /**
   * Read and return the entire contents of the supplied {@link InputStream}. This method always closes the stream when finished
   * reading.
   * 
   * @param stream the streamed contents; may be null
   * @return the contents, or an empty string if the supplied stream is null
   * @throws IOException if there is an error reading the content
   */
  public static String read( InputStream stream ) throws IOException {
      return stream == null ? "" : read(new InputStreamReader(stream));
  }
  /**
   * Read and return the entire contents of the supplied {@link Reader}. This method always closes the reader when finished
   * reading.
   * 
   * @param reader the reader of the contents; may be null
   * @return the contents, or an empty string if the supplied reader is null
   * @throws IOException if there is an error reading the content
   */
  public static String read( Reader reader ) throws IOException {
      if (reader == null) return "";
      StringBuilder sb = new StringBuilder();
      boolean error = false;
      try {
          int numRead = 0;
          char[] buffer = new char[1024];
          while ((numRead = reader.read(buffer)) > -1) {
              sb.append(buffer, 0, numRead);
          }
      } catch (IOException e) {
          error = true; // this error should be thrown, even if there is an error closing reader
          throw e;
      } catch (RuntimeException e) {
          error = true; // this error should be thrown, even if there is an error closing reader
          throw e;
      } finally {
          try {
              reader.close();
          } catch (IOException e) {
              if (!error) throw e;
          }
      }
      return sb.toString();
  }
}





Reads at most certain bytes from input stream and returns them as a byte array.

  
/*
 * Copyright Aduna (http://www.aduna-software.ru/) (c) 1997-2006.
 *
 * Licensed under the Aduna BSD-style license.
 */
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Main {
  /**
   * Reads at most <tt>maxBytes</tt> bytes from the supplied input stream and
   * returns them as a byte array.
   *
   * @param in The InputStream supplying the bytes.
   * @param maxBytes The maximum number of bytes to read from the input
   * stream.
   * @return A byte array of size <tt>maxBytes</tt> if the input stream can
   * produce that amount of bytes, or a smaller byte containing all available
   * bytes from the stream otherwise.
   */
  public static final byte[] readBytes(InputStream in, int maxBytes)
    throws IOException
  {
    byte[] result = new byte[maxBytes];
    int bytesRead = in.read(result);
    int totalBytesRead = bytesRead;
    while (totalBytesRead < maxBytes && bytesRead >= 0) {
      // Read more bytes
      bytesRead = in.read(result, bytesRead, maxBytes - bytesRead);
      if (bytesRead > 0) {
        totalBytesRead += bytesRead;
      }
    }
    if (totalBytesRead < 0) {
      // InputStream at end-of-file
      result = new byte[0];
    }
    else if (totalBytesRead < maxBytes) {
      // Create smaller byte array
      byte[] tmp = new byte[totalBytesRead];
      System.arraycopy(result, 0, tmp, 0, totalBytesRead);
      result = tmp;
    }
    return result;
  }
}





Size Limit InputStream

  
/*
 * Input stream wrapper with a byte limit.
 * Copyright (C) 2004 Stephen Ostermiller
 * http://ostermiller.org/contact.pl?regarding=Java+Utilities
 *
 * This program 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.
 *
 * This program 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.  See the
 * GNU General Public License for more details.
 *
 * See COPYING.TXT for details.
 */
import java.io.*;
/**
 * An input stream wrapper that will read only a set number of bytes from the
 * underlying stream.
 *
 * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
 * @since ostermillerutils 1.04.00
 */
public class SizeLimitInputStream extends InputStream {
  /**
   * The input stream that is being protected.
   * All methods should be forwarded to it,
   * after checking the size that has been read.
   *
   * @since ostermillerutils 1.04.00
   */
  protected InputStream in;
  /**
   * The number of bytes to read at most from this
   * Stream.  Read methods should
   * check to ensure that bytesRead never
   * exceeds maxBytesToRead.
   *
   * @since ostermillerutils 1.04.00
   */
  protected long maxBytesToRead = 0;
  /**
   * The number of bytes that have been read
   * from this stream.  Read methods should
   * check to ensure that bytesRead never
   * exceeds maxBytesToRead.
   *
   * @since ostermillerutils 1.04.00
   */
  protected long bytesRead = 0;
  /**
   * The number of bytes that have been read
   * from this stream since mark() was called.
   *
   * @since ostermillerutils 1.04.00
   */
  protected long bytesReadSinceMark = 0;
  /**
   * The number of bytes the user has request
   * to have been marked for reset.
   *
   * @since ostermillerutils 1.04.00
   */
  protected long markReadLimitBytes = -1;
  /**
   * Get the number of bytes actually read
   * from this stream.
   *
   * @return number of bytes that have already been taken from this stream.
   *
   * @since ostermillerutils 1.04.00
   */
  public long getBytesRead(){
    return bytesRead;
  }
  /**
   * Get the maximum number of bytes left to read
   * before the limit (set in the constructor) is reached.
   *
   * @return The number of bytes that (at a maximum) are left to be taken from this stream.
   *
   * @since ostermillerutils 1.04.00
   */
  public long getBytesLeft(){
    return maxBytesToRead - bytesRead;
  }
  /**
   * Tell whether the number of bytes specified
   * in the constructor have been read yet.
   *
   * @return true iff the specified number of bytes have all been read.
   *
   * @since ostermillerutils 1.04.00
   */
  public boolean allBytesRead(){
    return getBytesLeft() == 0;
  }
  /**
   * Get the number of total bytes (including bytes already read)
   * that can be read from this stream (as set in the constructor).
   * @return Maximum bytes that can be read until the size limit runs out
   *
   * @since ostermillerutils 1.04.00
   */
  public long getMaxBytesToRead(){
    return maxBytesToRead;
  }
  /**
   * Create a new size limit input stream from
   * another stream given a size limit.
   *
   * @param in The input stream.
   * @param maxBytesToRead the max number of bytes to allow to be read from the underlying stream.
   *
   * @since ostermillerutils 1.04.00
   */
  public SizeLimitInputStream(InputStream in, long maxBytesToRead){
    this.in = in;
    this.maxBytesToRead = maxBytesToRead;
  }
  /**
   * {@inheritDoc}
   */
  @Override public int read() throws IOException {
    if (bytesRead >= maxBytesToRead){
      return -1;
    }
    int b = in.read();
    if(b != -1){
      bytesRead++;
      bytesReadSinceMark++;
    }
    return b;
  }
  /**
   * {@inheritDoc}
   */
  @Override public int read(byte[] b) throws IOException {
    return this.read(b, 0, b.length);
  }
  /**
   * {@inheritDoc}
   */
  @Override public int read(byte[] b, int off, int len) throws IOException {
    if (bytesRead >= maxBytesToRead){
      return -1;
    }
    long bytesLeft = getBytesLeft();
    if (len > bytesLeft){
      len = (int)bytesLeft;
    }
    int bytesJustRead = in.read(b, off, len);
    bytesRead += bytesJustRead;
    bytesReadSinceMark += bytesJustRead;
    return bytesJustRead;
  }
  /**
   * {@inheritDoc}
   */
  @Override public long skip(long n) throws IOException {
    if (bytesRead >= maxBytesToRead){
      return -1;
    }
    long bytesLeft = getBytesLeft();
    if (n > bytesLeft){
      n = bytesLeft;
    }
    return in.skip(n);
  }
  /**
   * {@inheritDoc}
   */
  @Override public int available() throws IOException {
    int available = in.available();
    long bytesLeft = getBytesLeft();
    if (available > bytesLeft){
      available = (int)bytesLeft;
    }
    return available;
  }
  /**
   * Close this stream and underlying streams.
   * Calling this method may make data on the
   * underlying stream unavailable.
   * <p>
   * Consider wrapping this stream in a NoCloseStream
   * so that clients can
   * call close() with no effect.
   *
   * @since ostermillerutils 1.04.00
   */
  @Override public void close() throws IOException {
    in.close();
  }
  /**
   * {@inheritDoc}
   */
  @Override public void mark(int readlimit){
    if (in.markSupported()){
      markReadLimitBytes = readlimit;
      bytesReadSinceMark = 0;
      in.mark(readlimit);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override public void reset() throws IOException {
    if (in.markSupported() && bytesReadSinceMark <= markReadLimitBytes){
      bytesRead -= bytesReadSinceMark;
      in.reset();
      bytesReadSinceMark = 0;
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override public boolean markSupported(){
    return in.markSupported();
  }
}