StreamUtils.java
/*
* StreamUtils
*
* $Id$
* $HeadURL$
*/
package gov.usgs.util;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilterInputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.zip.GZIPInputStream;
/**
* Stream input, output, and transfer utilities.
*/
public class StreamUtils {
/** Default buffer size used for stream reads and writes. */
public static final int DEFAULT_BUFFER_SIZE = 4096;
/** Default connect timeout for url connections. */
public static final int DEFAULT_URL_CONNECT_TIMEOUT = 5000;
/** Default read timeout for url connections. */
public static final int DEFAULT_URL_READ_TIMEOUT = 15000;
/**
* Get an input stream for an Object if possible.
*
* @param obj
* an InputStream, File, byte[], or String.
* @return an InputStream or null. If obj is a File, the stream is Buffered.
* @throws IOException
* if an error occurs.
* @throws IllegalArgumentException
* if obj is not an InputStream, URL, File, byte[], or String.
*/
public static InputStream getInputStream(final Object obj)
throws IOException, IllegalArgumentException {
InputStream stream = null;
byte[] bytes = null;
if (obj instanceof InputStream) {
stream = (InputStream) obj;
} else if (obj instanceof URL) {
stream = getURLInputStream((URL) obj);
} else if (obj instanceof File) {
stream = new BufferedInputStream(new FileInputStream((File) obj));
} else if (obj instanceof byte[]) {
bytes = (byte[]) obj;
} else if (obj instanceof String) {
bytes = ((String) obj).getBytes();
} else {
throw new IllegalArgumentException(
"Expected an InputStream, URL, File, byte[], or String");
}
if (bytes != null) {
stream = new ByteArrayInputStream(bytes);
}
return stream;
}
/**
* Get an InputStream from a URL. If URL is a HTTP url, attempts gzip
* compression.
*
* @param url
* the url being accessed.
* @return an InputStream to content at URL.
* @throws IOException
* if an error occurs.
*/
public static InputStream getURLInputStream(final URL url)
throws IOException {
return getURLInputStream(url, DEFAULT_URL_CONNECT_TIMEOUT,
DEFAULT_URL_READ_TIMEOUT);
}
/**
* Get an InputStream from a URL. If URL is a HTTP url, attempts gzip
* compression.
*
* @param url
* the url being accessed.
* @param connectTimeout allowed time in milliseconds before connection.
* @param readTimeout allowed time in milliseconds before read.
* @return an InputStream to content at URL.
* @throws IOException
* if an error occurs.
*/
public static InputStream getURLInputStream(final URL url,
final int connectTimeout, final int readTimeout)
throws IOException {
InputStream in = null;
// initialize connection
URLConnection conn = url.openConnection();
conn.setRequestProperty("Accept-Encoding", "gzip");
conn.setConnectTimeout(connectTimeout);
conn.setReadTimeout(readTimeout);
// connect
conn.connect();
// get response
in = conn.getInputStream();
String contentEncoding = conn.getContentEncoding();
if (contentEncoding != null && contentEncoding.equals("gzip")) {
in = new GZIPInputStream(in);
}
return in;
}
/**
* Turn an object into an OutputStream if possible.
*
* @param obj
* an OutputStream or File.
* @param append
* if obj is a file and this parameter is true, the output stream
* will be opened in append mode.
* @return an OutputStream. If obj is a File, the stream is Buffered.
* @throws IOException
* if an error occurs
*/
public static OutputStream getOutputStream(final Object obj,
final boolean append) throws IOException {
OutputStream stream = null;
if (obj instanceof OutputStream) {
stream = (OutputStream) obj;
} else if (obj instanceof File) {
File file = (File) obj;
// create parent directory first, if needed
File parent = file.getAbsoluteFile().getParentFile();
if (!parent.exists() && !parent.mkdirs()) {
throw new IOException("Unable to create directory "
+ parent.getAbsolutePath());
}
if (!parent.canWrite()) {
throw new IOException(
"Do not have write permission for directory "
+ parent.getAbsolutePath());
}
stream = new BufferedOutputStream(
new FileOutputStream(file, append));
} else {
throw new IllegalArgumentException(
"Expected an OutputStream or File");
}
return stream;
}
/**
* Same as calling getOutputStream(obj, false). If obj is a file, it will
* open a new output stream and will not append.
*
* @param obj
* an OutputStream or File.
* @return an OutputStream. If obj is a File, the stream is Buffered.
* @throws IOException
* if an error occurs.
*/
public static OutputStream getOutputStream(final Object obj)
throws IOException {
return getOutputStream(obj, false);
}
/**
* Read stream contents into a byte array.
*
* @param from
* stream to read.
* @return byte array of file content.
* @throws IOException
* if an error occurs while reading.
*/
public static byte[] readStream(final Object from) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
transferStream(from, buffer);
return buffer.toByteArray();
}
/**
* Transfer contents of Object from to Object to.
*
* Calls transferStream(from, to, DEFAULT_BUFFER_SIZE).
*
* @param from
* streamable source.
* @param to
* streamable target.
* @throws IOException
* if IO error occurs
*/
public static void transferStream(final Object from, final Object to)
throws IOException {
transferStream(from, to, DEFAULT_BUFFER_SIZE);
}
/**
* Transfer contents of Object from to Object to. Uses getInputStream and
* getOutputStream to generate streams. Streams are closed after reading.
*
* @param from
* streamable source.
* @param to
* streamable target.
* @param bufferSize
* size of buffer
* @throws IOException
* if thrown by calls to read/write on streams.
*/
public static void transferStream(final Object from, final Object to,
final int bufferSize) throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = getInputStream(from);
out = getOutputStream(to);
byte[] buffer = new byte[bufferSize];
int read;
while ((read = in.read(buffer, 0, bufferSize)) != -1) {
out.write(buffer, 0, read);
}
closeStream(in);
closeStream(out);
} catch (Exception e) {
closeStream(in);
closeStream(out);
if (e instanceof IOException) {
throw (IOException) e;
}
}
}
/**
* Close an InputStream or OutputStream.
*
* @param stream
* stream to close.
*/
public static void closeStream(final Object stream) {
try {
if (stream instanceof OutputStream) {
OutputStream out = (OutputStream) stream;
try {
out.flush();
} finally {
out.close();
}
} else if (stream instanceof InputStream) {
((InputStream) stream).close();
}
} catch (Exception e) {
// ignore
}
}
/**
* An InputStream that ignores calls to close.
*
* Used for methods that automatically close a stream at EOF, even though it
* is undesirable for the stream to be closed, such as when using a
* ZipInputStream.
*
* @author jmfee
*
*/
public static class UnclosableInputStream extends FilterInputStream {
/**
* Create a new UnclosableInputStream object.
*
* @param in
* the InputStream to wrap.
*/
public UnclosableInputStream(final InputStream in) {
super(in);
}
/**
* Does not close stream.
*/
public void close() {
// ignore
}
}
/**
* An OutputStream that ignores calls to close.
*
* Used for methods that automatically close a stream, even though it is
* undesirable for the stream to be closed, such as when using a
* ZipOutputStream.
*
* @author jmfee
*
*/
public static class UnclosableOutputStream extends FilterOutputStream {
/**
* Create a new UnclosableOutputStream object.
*
* @param out
* the OutputStream to wrap.
*/
public UnclosableOutputStream(final OutputStream out) {
super(out);
}
/**
* Flush written content, but does not close stream.
*/
public void close() throws IOException {
out.flush();
// otherwise ignore
}
}
}