Java Tutorial/File/FilterInputStream
Содержание
An limited-data-size input stream
<source lang="java">
/*
* 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 anint
in the range *0
to255
. 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. * * This method * simply performsin.read()
and returns the result. * * @return the next byte of data, or-1
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 tolen
bytes of data from this input stream * into an array of bytes. Iflen
is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and0
is returned. * * This method simply performsin.read(b, off, len)
* and returns the result. * * @param b the buffer into which the data is read. * @param off The start offset in the destination array *b
. * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or *-1
if there is no more data because the end of * the stream has been reached. * @exception NullPointerException Ifb
isnull
. * @exception IndexOutOfBoundsException Ifoff
is negative, *len
is negative, orlen
is greater than *b.length - off
* @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 performsin.close()
. * * @exception IOException if an I/O error occurs. * @see java.io.FilterInputStream#in */ public void close() throws IOException { closed = true; super.close(); }
}</source>
A trace of the data that is being retrieved from an input stream
<source lang="java">
/*
* 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 *-1
if no data is available. Writes out the read * byte into the trace stream, if trace mode istrue
*/ 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 tolen
bytes of data from this input stream * into an array of bytes. Returns-1
if no more data * is available. Writes out the read bytes into the trace stream, if * trace mode istrue
*/ 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); } }
}</source>
introduce a protocol for reading arbitrary length data in a uniform way
<source lang="java">
/*
* 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.DataInputStream; import java.io.FilterInputStream; import java.io.InputStream; import java.io.IOException; /**
* This input stream works in conjunction with the WrappedOutputStream * to introduce a protocol for reading arbitrary length data in a * uniform way. * * Note: See the javadoc for WrappedOutputStream for * more information. * * @see WrappedOutputStream * * @author Andy Clark, IBM * * @version $Id: WrappedInputStream.java 447688 2006-09-19 02:39:49Z mrglavas $ */
public class WrappedInputStream
extends FilterInputStream { // // Data // /** Bytes left on input stream for current packet. */ protected int fPacketCount; /** * Data input stream. This stream is used to input the block sizes * from the data stream that are written by the WrappedOutputStream. * * Note: The data input stream is only used for * reading the byte count for performance reasons. We avoid the * method indirection for reading the byte data. */ protected DataInputStream fDataInputStream; /** To mark that the stream is "closed". */ protected boolean fClosed; // // Constructors // /** Constructs a wrapper for the given an input stream. */ public WrappedInputStream(InputStream stream) { super(stream); fDataInputStream = new DataInputStream(stream); } // <init>(InputStream) // // InputStream methods // /** Reads a single byte. */ public int read() throws IOException { // ignore, if already closed if (fClosed) { return -1; } // read packet header if (fPacketCount == 0) { fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; if (fPacketCount == 0) { fClosed = true; return -1; } } // read a byte from the packet fPacketCount--; return super.in.read(); } // read():int /** * Reads a block of bytes and returns the total number of bytes read. */ public int read(byte[] b, int offset, int length) throws IOException { // ignore, if already closed if (fClosed) { return -1; } // read packet header if (fPacketCount == 0) { fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; if (fPacketCount == 0) { fClosed = true; return -1; } } // read bytes from packet if (length > fPacketCount) { length = fPacketCount; } int count = super.in.read(b, offset, length); if (count == -1) { // NOTE: This condition should not happen. The end of // the stream should always be designated by a // byte count header of 0. -Ac fClosed = true; return -1; } fPacketCount -= count; // return total bytes read return count; } // read(byte[],int,int):int /** Skips the specified number of bytes from the input stream. */ public long skip(long n) throws IOException { if (!fClosed) { // NOTE: This should be rewritten to be more efficient. -Ac for (long i = 0; i < n; i++) { int b = read(); if (b == -1) { return i + 1; } } return n; } return 0; } // skip(long):long /** * Closes the input stream. This method will search for the end of * the wrapped input, positioning the stream at after the end packet. * * Note: This method does not close the underlying * input stream. */ public void close() throws IOException { if (!fClosed) { fClosed = true; do { super.in.skip(fPacketCount); fPacketCount = fDataInputStream.readInt() & 0x7FFFFFFF; } while (fPacketCount > 0); } } // close()
} // class WrappedInputStream /*
* 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.DataOutputStream; import java.io.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; /**
* This output stream works in conjunction with the WrappedInputStream
* to introduce a protocol for sending arbitrary length data in a
* uniform way. This output stream allows variable length data to be
* inserted into an existing output stream so that it can be read by
* an input stream without reading too many bytes (in case of buffering
* by the input stream).
*
* This output stream is used like any normal output stream. The protocol
* is introduced by the WrappedOutputStream and does not need to be known
* by the user of this class. However, for those that are interested, the
* method is described below.
*
* The output stream writes the requested bytes as packets of binary
* information. The packet consists of a header and payload. The header
* is two bytes of a single unsigned short (written in network order)
* that specifies the length of bytes in the payload. A header value of
* 0 indicates that the stream is "closed".
*
* Note: For this wrapped output stream to be used,
* the application must call close()
* to end the output.
*
* @see WrappedInputStream
*
* @author Andy Clark, IBM
*
* @version $Id: WrappedOutputStream.java 447688 2006-09-19 02:39:49Z mrglavas $
*/
public class WrappedOutputStream
extends FilterOutputStream { // // Constants // /** Default buffer size (1024). */ public static final int DEFAULT_BUFFER_SIZE = 1024; // // Data // /** Buffer. */ protected byte[] fBuffer; /** Buffer position. */ protected int fPosition; /** * Data output stream. This stream is used to output the block sizes * into the data stream that are read by the WrappedInputStream. * * Note: The data output stream is only used for * writing the byte count for performance reasons. We avoid the * method indirection for writing the byte data. */ protected DataOutputStream fDataOutputStream; // // Constructors // /** Constructs a wrapper for the given output stream. */ public WrappedOutputStream(OutputStream stream) { this(stream, DEFAULT_BUFFER_SIZE); } // <init>(OutputStream) /** * Constructs a wrapper for the given output stream with the * given buffer size. */ public WrappedOutputStream(OutputStream stream, int bufferSize) { super(stream); fBuffer = new byte[bufferSize]; fDataOutputStream = new DataOutputStream(stream); } // <init>(OutputStream) // // OutputStream methods // /** * Writes a single byte to the output. * * Note: Single bytes written to the output stream * will be buffered */ public void write(int b) throws IOException { fBuffer[fPosition++] = (byte)b; if (fPosition == fBuffer.length) { fPosition = 0; fDataOutputStream.writeInt(fBuffer.length); super.out.write(fBuffer, 0, fBuffer.length); } } // write(int) /** Writes an array of bytes to the output. */ public void write(byte[] b, int offset, int length) throws IOException { // flush existing buffer if (fPosition > 0) { flush0(); } // write header followed by actual bytes fDataOutputStream.writeInt(length); super.out.write(b, offset, length); } // write(byte[]) /** * Flushes the output buffer, writing all bytes currently in * the buffer to the output. */ public void flush() throws IOException { flush0(); super.out.flush(); } // flush() /** * Closes the output stream. This method must be * called when done writing all data to the output stream. * * Note: This method does not close the * actual output stream, only makes the input stream see the stream * closed. Do not write bytes after closing the output stream. */ public void close() throws IOException { flush0(); fDataOutputStream.writeInt(0); super.out.flush(); } // close() // // Protected methods // /** * Flushes the output buffer, writing all bytes currently in * the buffer to the output. This method does not call the * flush() method of the output stream; it merely writes the * remaining bytes in the buffer. */ public void flush0() throws IOException { int length = fPosition; fPosition = 0; if (length > 0) { fDataOutputStream.writeInt(length); super.out.write(fBuffer, 0, length); } } // flush0()
} // class WrappedOutputStream</source>
Reads from an underlying InputStream up to a defined number of bytes or the end of the underlying stream
<source lang="java">
/*
* 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. */
/* $Id: SubInputStream.java 604883 2007-12-17 14:36:37Z jeremias $ */
import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /**
* This class is a FilterInputStream descendant that reads from an underlying InputStream * up to a defined number of bytes or the end of the underlying stream. Closing this InputStream * will not result in the underlying InputStream to be closed, too. * * This InputStream can be used to read chunks from a larger file of which the length is * known in advance. */
public class SubInputStream extends FilterInputStream {
/** Indicates the number of bytes remaining to be read from the underlying InputStream. */ private long bytesToRead; /** * Indicates whether the underlying stream should be closed when the {@link #close()} method * is called. */ private boolean closeUnderlying = false; /** * Creates a new SubInputStream. * @param in the InputStream to read from * @param maxLen the maximum number of bytes to read from the underlying InputStream until * the end-of-file is signalled. * @param closeUnderlying true if the underlying stream should be closed when the * {@link #close()} method is called. */ public SubInputStream(InputStream in, long maxLen, boolean closeUnderlying) { super(in); this.bytesToRead = maxLen; this.closeUnderlying = closeUnderlying; } /** * Creates a new SubInputStream. The underlying stream is not closed, when close() is called. * @param in the InputStream to read from * @param maxLen the maximum number of bytes to read from the underlying InputStream until * the end-of-file is signalled. */ public SubInputStream(InputStream in, long maxLen) { this(in, maxLen, false); } /** {@inheritDoc} */ public int read() throws IOException { if (bytesToRead > 0) { int result = super.read(); if (result >= 0) { bytesToRead--; return result; } else { return -1; } } else { return -1; } } /** {@inheritDoc} */ public int read(byte[] b, int off, int len) throws IOException { if (bytesToRead == 0) { return -1; } int effRead = (int)Math.min(bytesToRead, len); //cast to int is safe because len can never be bigger than Integer.MAX_VALUE int result = super.read(b, off, effRead); if (result >= 0) { bytesToRead -= result; } return result; } /** {@inheritDoc} */ public long skip(long n) throws IOException { long effRead = Math.min(bytesToRead, n); long result = super.skip(effRead); bytesToRead -= result; return result; } /** {@inheritDoc} */ public void close() throws IOException { this.bytesToRead = 0; if (this.closeUnderlying) { super.close(); } }
} ////////////////////////////////// /*
* 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. */
/* $Id: SubInputStreamTestCase.java 604883 2007-12-17 14:36:37Z jeremias $ */
package org.apache.xmlgraphics.util.io; import java.io.ByteArrayInputStream; import java.util.Arrays; import junit.framework.TestCase; /**
* Test case for SubInputStream. */
public class SubInputStreamTestCase extends TestCase {
/** * Main constructor. * @param name the test case"s name * @see junit.framework.TestCase#TestCase(String) */ public SubInputStreamTestCase(String name) { super(name); } /** * Tests SubInputStream. * @throws Exception if an error occurs */ public void testMain() throws Exception { //Initialize test data byte[] data = new byte[256]; for (int i = 0; i < data.length; i++) { data[i] = (byte)(i & 0xff); } int v, c; byte[] buf; String s; SubInputStream subin = new SubInputStream(new ByteArrayInputStream(data), 10); v = subin.read(); assertEquals(0, v); v = subin.read(); assertEquals(1, v); buf = new byte[4]; c = subin.read(buf); assertEquals(4, c); s = new String(buf, "US-ASCII"); assertEquals("\u0002\u0003\u0004\u0005", s); Arrays.fill(buf, (byte)0); c = subin.read(buf, 2, 2); assertEquals(2, c); s = new String(buf, "US-ASCII"); assertEquals("\u0000\u0000\u0006\u0007", s); Arrays.fill(buf, (byte)0); c = subin.read(buf); assertEquals(2, c); s = new String(buf, "US-ASCII"); assertEquals("\u0008\u0009\u0000\u0000", s); }
}</source>