All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pepsoft.util.StreamUtils Maven / Gradle / Ivy

The newest version!
package org.pepsoft.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * Utility methods for working with {@link InputStream}s and {@link OutputStream}s.
 */
public class StreamUtils {
    private StreamUtils() {
        // Prevent instantiation
    }

    /**
     * Load all bytes from an input stream and close it. Note that there may
     * not be more than {@link Integer#MAX_VALUE} bytes left in the stream.
     *
     * @param in The input stream to load.
     * @return All bytes from the input stream.
     * @throws IOException If an I/O error occurs while loading the bytes or
     * closing the stream.
     */
    public static byte[] load(InputStream in) throws IOException {
        try {
            try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
                byte[] buffer = BUFFERS.get();
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
                in.close();
                return out.toByteArray();
            }
        } finally {
            // Don't obscure an existing exception with a secondary exception
            try {
                in.close();
            } catch (IOException | Error | RuntimeException e) {
                System.err.println("StreamUtils.load(InputStream): secondary I/O error while closing input stream");
                e.printStackTrace();
            }
        }
    }

    /**
     * Copy all bytes from the input stream to the output stream and close both
     * streams.
     *
     * @param in  The input stream to copy from.
     * @param out The output stream to copy to.
     * @throws IOException If an I/O error occurs while copying the bytes or
     *                     closing the streams.
     */
    public static void copy(InputStream in, OutputStream out) throws IOException {
        try {
            copy(in, out, null, -1);
        } catch (ProgressReceiver.OperationCancelled e) {
            // This can't happen since we didn't provide a progress receiver.
            throw new InternalError(e);
        }
    }

    /**
     * Copy all bytes (up to a specified maximum) from the input stream to the
     * output stream and close both streams. This version allows the
     * specification of a maximum number of bytes to copy. If the input stream
     * contains more bytes, the method throws an {@link IOException}.
     *
     * @param in  The input stream to copy from.
     * @param out The output stream to copy to.
     * @param maximumBytes The maximum number of bytes to allow in the input
     *                     stream.
     * @throws IOException If an I/O error occurs while copying the bytes or
     *                     closing the streams, or if the input stream contained
     *                     more than the specified number of bytes.
     */
    public static void copy(InputStream in, OutputStream out, int maximumBytes) throws IOException {
        try {
            copy(in, out, null, maximumBytes);
        } catch (ProgressReceiver.OperationCancelled e) {
            // This can't happen since we didn't provide a progress receiver.
            throw new InternalError(e);
        }
    }

    /**
     * Copy all bytes from the input stream to the output stream and close both
     * streams.
     *
     * @param in The input stream to copy from.
     * @param out The output stream to copy to.
     * @param progressReceiver An optional progress receiver to report copy
     *                         progress to.
     * @param byteCount The number of bytes in the input stream. If the input
     *                  stream contains more bytes, an
     *                  {@link IOException} is thrown. Specify {@code -1} to
     *                  disable a byte limit. If a progress receiver is
     *                  specified then this parameter is mandatory.
     * @throws IOException If an I/O error occurs while copying the bytes or
     *                     closing the streams, or if there were more.
     * @throws ProgressReceiver.OperationCancelled If a progress receiver was
     * provided and it threw an {@code OperationCancelled} exception.
     */
    public static void copy(InputStream in, OutputStream out, ProgressReceiver progressReceiver, long byteCount) throws IOException, ProgressReceiver.OperationCancelled {
        try {
            try {
                byte[] buffer = BUFFERS.get();
                int bytesRead;
                long bytesReadTotal = 0;
                while ((bytesRead = in.read(buffer)) != -1) {
                    if ((byteCount > 0) && (bytesReadTotal + bytesRead > byteCount)) {
                        throw new IOException("Too many bytes in input stream (limit: " + byteCount + "; bytes read so far: " + (bytesReadTotal + bytesRead) + ")");
                    }
                    out.write(buffer, 0, bytesRead);
                    bytesReadTotal += bytesRead;
                    if ((progressReceiver != null) && (byteCount > 0L)) {
                        progressReceiver.setProgress((float) bytesReadTotal / byteCount);
                    }
                }
                in.close();
                out.close();
            } finally {
                // Don't obscure an existing exception with a secondary exception
                try {
                    in.close();
                } catch (IOException | Error | RuntimeException e) {
                    System.err.println("StreamUtils.copy(InputStream, OutputStream, ProgressReceiver, long): secondary I/O error while closing input stream");
                    e.printStackTrace();
                }
            }
        } finally {
            // Don't obscure an existing exception with a secondary exception
            try {
                out.close();
            } catch (IOException | Error | RuntimeException e) {
                System.err.println("StreamUtils.copy(InputStream, OutputStream, ProgressReceiver, long): secondary I/O error while closing output stream");
                e.printStackTrace();
            }
        }
    }

    private static final int BUFFER_SIZE = 32768;
    private static final ThreadLocal BUFFERS = ThreadLocal.withInitial(() -> new byte[BUFFER_SIZE]);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy