/*
 * 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.
 */
package org.apache.tomcat.util.http.fileupload;

import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

General IO stream manipulation utilities.

This class provides static utility methods for input/output operations.

  • closeQuietly - these methods close a stream ignoring nulls and exceptions
  • toXxx/read - these methods read data from a stream
  • write - these methods write data to a stream
  • copy - these methods copy all the data from one stream to another
  • contentEquals - these methods compare the content of two streams

The byte-to-char methods and char-to-byte methods involve a conversion step. Two methods are provided in each case, one that uses the platform default encoding and the other which allows you to specify an encoding. You are encouraged to always specify an encoding because relying on the platform default can lead to unexpected results, for example when moving from development to production.

All the methods in this class that read a stream are buffered internally. This means that there is no cause to use a BufferedInputStream or BufferedReader. The default buffer size of 4K has been shown to be efficient in tests.

Wherever possible, the methods in this class do not flush or close the stream. This is to avoid making non-portable assumptions about the streams' origin and further use. Thus the caller is still responsible for closing streams after use.

Origin of code: Excalibur.

/** * General IO stream manipulation utilities. * <p> * This class provides static utility methods for input/output operations. * <ul> * <li>closeQuietly - these methods close a stream ignoring nulls and exceptions * <li>toXxx/read - these methods read data from a stream * <li>write - these methods write data to a stream * <li>copy - these methods copy all the data from one stream to another * <li>contentEquals - these methods compare the content of two streams * </ul> * <p> * The byte-to-char methods and char-to-byte methods involve a conversion step. * Two methods are provided in each case, one that uses the platform default * encoding and the other which allows you to specify an encoding. You are * encouraged to always specify an encoding because relying on the platform * default can lead to unexpected results, for example when moving from * development to production. * <p> * All the methods in this class that read a stream are buffered internally. * This means that there is no cause to use a <code>BufferedInputStream</code> * or <code>BufferedReader</code>. The default buffer size of 4K has been shown * to be efficient in tests. * <p> * Wherever possible, the methods in this class do <em>not</em> flush or close * the stream. This is to avoid making non-portable assumptions about the * streams' origin and further use. Thus the caller is still responsible for * closing streams after use. * <p> * Origin of code: Excalibur. */
public class IOUtils { // NOTE: This class is focused on InputStream, OutputStream, Reader and // Writer. Each method should take at least one of these as a parameter, // or return one of them.
Represents the end-of-file (or stream).
Since:2.5 (made public)
/** * Represents the end-of-file (or stream). * @since 2.5 (made public) */
public static final int EOF = -1;
The default buffer size (4096) to use for copyLarge(InputStream, OutputStream).
/** * The default buffer size ({@value}) to use for * {@link #copyLarge(InputStream, OutputStream)}. */
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
Closes a Closeable unconditionally.

Equivalent to Closeable.close(), except any exceptions will be ignored. This is typically used in finally blocks.

Example code:

Closeable closeable = null;
try {
    closeable = new FileReader("foo.txt");
    // process closeable
    closeable.close();
} catch (Exception e) {
    // error handling
} finally {
    IOUtils.closeQuietly(closeable);
}

Closing all streams:

try {
    return IOUtils.copy(inputStream, outputStream);
} finally {
    IOUtils.closeQuietly(inputStream);
    IOUtils.closeQuietly(outputStream);
}
Params:
  • closeable – the objects to close, may be null or already closed
Since:2.0
/** * Closes a <code>Closeable</code> unconditionally. * <p> * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in * finally blocks. * <p> * Example code: * </p> * <pre> * Closeable closeable = null; * try { * closeable = new FileReader(&quot;foo.txt&quot;); * // process closeable * closeable.close(); * } catch (Exception e) { * // error handling * } finally { * IOUtils.closeQuietly(closeable); * } * </pre> * <p> * Closing all streams: * </p> * <pre> * try { * return IOUtils.copy(inputStream, outputStream); * } finally { * IOUtils.closeQuietly(inputStream); * IOUtils.closeQuietly(outputStream); * } * </pre> * * @param closeable the objects to close, may be null or already closed * @since 2.0 */
public static void closeQuietly(final Closeable closeable) { try { if (closeable != null) { closeable.close(); } } catch (final IOException ioe) { // ignore } } // copy from InputStream //-----------------------------------------------------------------------
Copies bytes from an InputStream to an OutputStream.

This method buffers the input internally, so there is no need to use a BufferedInputStream.

Large streams (over 2GB) will return a bytes copied value of -1 after the copy has completed since the correct number of bytes cannot be returned as an int. For large streams use the copyLarge(InputStream, OutputStream) method.

Params:
  • input – the InputStream to read from
  • output – the OutputStream to write to
Throws:
Returns:the number of bytes copied, or -1 if > Integer.MAX_VALUE
Since:1.1
/** * Copies bytes from an <code>InputStream</code> to an * <code>OutputStream</code>. * <p> * This method buffers the input internally, so there is no need to use a * <code>BufferedInputStream</code>. * <p> * Large streams (over 2GB) will return a bytes copied value of * <code>-1</code> after the copy has completed since the correct * number of bytes cannot be returned as an int. For large streams * use the <code>copyLarge(InputStream, OutputStream)</code> method. * * @param input the <code>InputStream</code> to read from * @param output the <code>OutputStream</code> to write to * @return the number of bytes copied, or -1 if &gt; Integer.MAX_VALUE * @throws NullPointerException if the input or output is null * @throws IOException if an I/O error occurs * @since 1.1 */
public static int copy(final InputStream input, final OutputStream output) throws IOException { final long count = copyLarge(input, output); if (count > Integer.MAX_VALUE) { return -1; } return (int) count; }
Copies bytes from a large (over 2GB) InputStream to an OutputStream.

This method buffers the input internally, so there is no need to use a BufferedInputStream.

The buffer size is given by DEFAULT_BUFFER_SIZE.

Params:
  • input – the InputStream to read from
  • output – the OutputStream to write to
Throws:
Returns:the number of bytes copied
Since:1.3
/** * Copies bytes from a large (over 2GB) <code>InputStream</code> to an * <code>OutputStream</code>. * <p> * This method buffers the input internally, so there is no need to use a * <code>BufferedInputStream</code>. * <p> * The buffer size is given by {@link #DEFAULT_BUFFER_SIZE}. * * @param input the <code>InputStream</code> to read from * @param output the <code>OutputStream</code> to write to * @return the number of bytes copied * @throws NullPointerException if the input or output is null * @throws IOException if an I/O error occurs * @since 1.3 */
public static long copyLarge(final InputStream input, final OutputStream output) throws IOException { byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; long count = 0; int n = 0; while (EOF != (n = input.read(buffer))) { output.write(buffer, 0, n); count += n; } return count; }
Reads bytes from an input stream. This implementation guarantees that it will read as many bytes as possible before giving up; this may not always be the case for subclasses of InputStream.
Params:
  • input – where to read input from
  • buffer – destination
  • offset – initial offset into buffer
  • length – length to read, must be >= 0
Throws:
Returns:actual length read; may be less than requested if EOF was reached
Since:2.2
/** * Reads bytes from an input stream. * This implementation guarantees that it will read as many bytes * as possible before giving up; this may not always be the case for * subclasses of {@link InputStream}. * * @param input where to read input from * @param buffer destination * @param offset initial offset into buffer * @param length length to read, must be &gt;= 0 * @return actual length read; may be less than requested if EOF was reached * @throws IOException if a read error occurs * @since 2.2 */
public static int read(final InputStream input, final byte[] buffer, final int offset, final int length) throws IOException { if (length < 0) { throw new IllegalArgumentException("Length must not be negative: " + length); } int remaining = length; while (remaining > 0) { final int location = length - remaining; final int count = input.read(buffer, offset + location, remaining); if (EOF == count) { // EOF break; } remaining -= count; } return length - remaining; }
Reads the requested number of bytes or fail if there are not enough left.

This allows for the possibility that InputStream.read(byte[], int, int) may not read as many bytes as requested (most likely because of reaching EOF).

Params:
  • input – where to read input from
  • buffer – destination
  • offset – initial offset into buffer
  • length – length to read, must be >= 0
Throws:
Since:2.2
/** * Reads the requested number of bytes or fail if there are not enough left. * <p> * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may * not read as many bytes as requested (most likely because of reaching EOF). * * @param input where to read input from * @param buffer destination * @param offset initial offset into buffer * @param length length to read, must be &gt;= 0 * * @throws IOException if there is a problem reading the file * @throws IllegalArgumentException if length is negative * @throws EOFException if the number of bytes read was incorrect * @since 2.2 */
public static void readFully(final InputStream input, final byte[] buffer, final int offset, final int length) throws IOException { final int actual = read(input, buffer, offset, length); if (actual != length) { throw new EOFException("Length to read: " + length + " actual: " + actual); } }
Reads the requested number of bytes or fail if there are not enough left.

This allows for the possibility that InputStream.read(byte[], int, int) may not read as many bytes as requested (most likely because of reaching EOF).

Params:
  • input – where to read input from
  • buffer – destination
Throws:
Since:2.2
/** * Reads the requested number of bytes or fail if there are not enough left. * <p> * This allows for the possibility that {@link InputStream#read(byte[], int, int)} may * not read as many bytes as requested (most likely because of reaching EOF). * * @param input where to read input from * @param buffer destination * * @throws IOException if there is a problem reading the file * @throws IllegalArgumentException if length is negative * @throws EOFException if the number of bytes read was incorrect * @since 2.2 */
public static void readFully(final InputStream input, final byte[] buffer) throws IOException { readFully(input, buffer, 0, buffer.length); } }