blob: 94690248aadac742d1ba7f223f70ac7599da62c8 [file] [log] [blame]
/*
* 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
*
* https://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.directory.api.util;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.directory.api.i18n.I18n;
/**
* This code comes from Apache commons.io library.
*
* Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public final class IOUtils
{
/**
* The default buffer size ({@value}) to use for
* {@link #copyLarge(InputStream, OutputStream)}
* and
* {@link #copyLarge(Reader, Writer)}
*/
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
/** The end of file */
private static final int EOF = -1;
/**
* Creates a new instance of FileUtils.
*/
private IOUtils()
{
// Nothing to do.
}
/**
* Closes an <code>InputStream</code> unconditionally.
* <p>
* Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
* This is typically used in finally blocks.
* <p>
* Example code:
* <pre>
* byte[] data = new byte[1024];
* InputStream in = null;
* try {
* in = new FileInputStream("foo.txt");
* in.read(data);
* in.close(); //close errors are handled
* } catch (Exception e) {
* // error handling
* } finally {
* IOUtils.closeQuietly(in);
* }
* </pre>
*
* @param input the InputStream to close, may be null or already closed
*/
public static void closeQuietly( InputStream input )
{
closeQuietly( ( Closeable ) input );
}
/**
* 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:
*
* <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>
*
* Closing all streams:
*
* <pre>
* try {
* return IOUtils.copy(inputStream, outputStream);
* } finally {
* IOUtils.closeQuietly(inputStream);
* IOUtils.closeQuietly(outputStream);
* }
* </pre>
*
* @param closeables the objects to close, may be null or already closed
* @since 2.5
*/
public static void closeQuietly( Closeable... closeables )
{
if ( closeables == null )
{
return;
}
for ( Closeable closeable : closeables )
{
closeQuietly( closeable );
}
}
/**
* 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:
*
* <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>
*
* Closing all streams:
*
* <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( Closeable closeable )
{
try
{
if ( closeable != null )
{
closeable.close();
}
}
catch ( IOException ioe )
{
// ignore
}
}
/**
* Gets the contents of an <code>InputStream</code> as a String
* using the specified character encoding.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* </p>
* @param input the <code>InputStream</code> to read from
* @param encoding the encoding to use, null means platform default
* @return the requested String
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static String toString( InputStream input, Charset encoding ) throws IOException
{
StringBuilderWriter sw = new StringBuilderWriter();
copy( input, sw, encoding );
return sw.toString();
}
/**
* Returns the given Charset or the default Charset if the given Charset is null.
*
* @param charset A charset or null.
* @return the given Charset or the default Charset if the given Charset is null
*/
public static Charset toCharset( Charset charset )
{
return charset == null ? Charset.defaultCharset() : charset;
}
/**
* Returns a Charset for the named charset. If the name is null, return the default Charset.
*
* @param charset The name of the requested charset, may be null.
* @return a Charset for the named charset
*/
public static Charset toCharset( String charset )
{
return charset == null ? Charset.defaultCharset() : Charset.forName( charset );
}
/**
* Copies bytes from an <code>InputStream</code> to chars on a
* <code>Writer</code> using the specified character encoding.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
* This method uses {@link InputStreamReader}.
*
* @param input the <code>InputStream</code> to read from
* @param output the <code>Writer</code> to write to
* @param inputEncoding the encoding to use for the input stream, null means platform default
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static void copy( InputStream input, Writer output, Charset inputEncoding ) throws IOException
{
InputStreamReader in = new InputStreamReader( input, toCharset( inputEncoding ) );
copy( in, output );
}
/**
* Copies chars from a <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
* Large streams (over 2GB) will return a chars copied value of
* <code>-1</code> after the copy has completed since the correct
* number of chars cannot be returned as an int. For large streams
* use the <code>copyLarge(Reader, Writer)</code> method.
*
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @return the number of characters 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( Reader input, Writer output ) throws IOException
{
long count = copyLarge( input, output );
if ( count > Integer.MAX_VALUE )
{
return -1;
}
return ( int ) count;
}
/**
* 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( InputStream input, OutputStream output ) throws IOException
{
long count = copyLarge( input, output );
if ( count > Integer.MAX_VALUE )
{
return -1;
}
return ( int ) count;
}
/**
* Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using an internal buffer of the
* given size.
* <p>
* This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>.
* <p>
*
* @param input
* the <code>InputStream</code> to read from
* @param output
* the <code>OutputStream</code> to write to
* @param bufferSize
* the bufferSize used to copy from the input to the output
* @return the number of bytes copied
* @throws NullPointerException
* if the input or output is null
* @throws IOException
* if an I/O error occurs
* @since 2.5
*/
public static long copy( InputStream input, OutputStream output, int bufferSize ) throws IOException
{
return copyLarge( input, output, new byte[bufferSize] );
}
/**
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
* The buffer size is given by #DEFAULT_BUFFER_SIZE.
*
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @return the number of characters 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( Reader input, Writer output ) throws IOException
{
return copyLarge( input, output, new char[DEFAULT_BUFFER_SIZE] );
}
/**
* 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 #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( InputStream input, OutputStream output ) throws IOException
{
return copy( input, output, DEFAULT_BUFFER_SIZE );
}
/**
* Copies bytes from a large (over 2GB) <code>InputStream</code> to an
* <code>OutputStream</code>.
* <p>
* This method uses the provided buffer, so there is no need to use a
* <code>BufferedInputStream</code>.
* <p>
*
* @param input the <code>InputStream</code> to read from
* @param output the <code>OutputStream</code> to write to
* @param buffer the buffer to use for the copy
* @return the number of bytes copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.2
*/
public static long copyLarge( InputStream input, OutputStream output, byte[] buffer ) throws IOException
{
long count = 0;
int n;
while ( EOF != ( n = input.read( buffer ) ) )
{
output.write( buffer, 0, n );
count += n;
}
return count;
}
/**
* Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>.
* <p>
* This method uses the provided buffer, so there is no need to use a
* <code>BufferedReader</code>.
* <p>
*
* @param input the <code>Reader</code> to read from
* @param output the <code>Writer</code> to write to
* @param buffer the buffer to be used for the copy
* @return the number of characters copied
* @throws NullPointerException if the input or output is null
* @throws IOException if an I/O error occurs
* @since 2.2
*/
public static long copyLarge( Reader input, Writer output, char[] buffer ) throws IOException
{
long count = 0;
int n;
while ( EOF != ( n = input.read( buffer ) ) )
{
output.write( buffer, 0, n );
count += n;
}
return count;
}
/**
* Writes chars from a <code>String</code> to bytes on an
* <code>OutputStream</code> using the specified character encoding.
* <p>
* This method uses {@link String#getBytes(String)}.
*
* @param data the <code>String</code> to write, null ignored
* @param output the <code>OutputStream</code> to write to
* @param encoding the encoding to use, null means platform default
* @throws NullPointerException if output is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static void write( String data, OutputStream output, Charset encoding ) throws IOException
{
if ( data != null )
{
output.write( data.getBytes( toCharset( encoding ) ) );
}
}
/**
* Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.
* Use this method instead of <code>toByteArray(InputStream)</code>
* when <code>InputStream</code> size is known
* @param input the <code>InputStream</code> to read from
* @param size the size of <code>InputStream</code>
* @return the requested byte array
* @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
* @throws IllegalArgumentException if size is less than zero
* @since 2.1
*/
public static byte[] toByteArray( InputStream input, int size ) throws IOException
{
if ( size < 0 )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17070_SIZE_POSITIVE, size ) );
}
if ( size == 0 )
{
return new byte[0];
}
byte[] data = new byte[size];
int offset = 0;
int readed = input.read( data, offset, size - offset );
while ( offset < size && ( readed != EOF ) )
{
offset += readed;
readed = input.read( data, offset, size - offset );
}
if ( offset != size )
{
throw new IOException( I18n.err( I18n.ERR_17071_UNEXPECTED_SIZE, offset, size ) );
}
return data;
}
/**
* Gets contents of an <code>InputStream</code> as a <code>byte[]</code>.
* Use this method instead of <code>toByteArray(InputStream)</code>
* when <code>InputStream</code> size is known.
* <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation
* before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array.
* (Arrays can have no more than Integer.MAX_VALUE entries anyway)
*
* @param input the <code>InputStream</code> to read from
* @param size the size of <code>InputStream</code>
* @return the requested byte array
* @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size
* @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE
* @see IOUtils#toByteArray(java.io.InputStream, int)
* @since 2.1
*/
public static byte[] toByteArray( InputStream input, long size ) throws IOException
{
if ( size > Integer.MAX_VALUE )
{
throw new IllegalArgumentException( I18n.err( I18n.ERR_17072_INTEGER_OVERFLOW, size ) );
}
return toByteArray( input, ( int ) size );
}
/**
* Gets the contents of an <code>InputStream</code> as a list of Strings,
* one entry per line, using the specified character encoding.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedInputStream</code>.
*
* @param input the <code>InputStream</code> to read from, not null
* @param encoding the encoding to use, null means platform default
* @return the list of Strings, never null
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
* @since 2.3
*/
public static List<String> readLines( InputStream input, Charset encoding ) throws IOException
{
InputStreamReader reader = new InputStreamReader( input, toCharset( encoding ) );
return readLines( reader );
}
/**
* Gets the contents of a <code>Reader</code> as a list of Strings,
* one entry per line.
* <p>
* This method buffers the input internally, so there is no need to use a
* <code>BufferedReader</code>.
*
* @param input the <code>Reader</code> to read from, not null
* @return the list of Strings, never null
* @throws NullPointerException if the input is null
* @throws IOException if an I/O error occurs
* @since 1.1
*/
public static List<String> readLines( Reader input ) throws IOException
{
BufferedReader reader = toBufferedReader( input );
List<String> list = new ArrayList<>();
String line = reader.readLine();
while ( line != null )
{
list.add( line );
line = reader.readLine();
}
return list;
}
/**
* Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given
* reader.
*
* @param reader
* the reader to wrap or return (not null)
* @return the given reader or a new {@link BufferedReader} for the given reader
* @since 2.2
* @throws NullPointerException if the input parameter is null
*/
public static BufferedReader toBufferedReader( Reader reader )
{
return reader instanceof BufferedReader ? ( BufferedReader ) reader : new BufferedReader( reader );
}
}