Hi,
In a dark corner of Excalibur lies a rather unexciting class called
IOUtils.java. It lets you copy between InputStreams and OutputStreams,
cleanly shut down streams, and that's it.
Over the last week I have ruthlessly expanded it's functionality, such
that there are now methods to copy from (InputStream|Reader|String) to
(OutputStream|Writer|String), with variants to select the buffer size
and (where appropriate) the byte->char encoding.
Example uses:
// Read text from a file to a String
String s = IOUtil.toString( new FileReader("foo.txt") );
// Copy the jakarta home page to a File:
IOUtil.copy(
new URL("http://jakarta.apache.org").openStream(),
new FileOutputStream("index.html")
).close();
etc.
Lots of Javadocs, and a test suite to ensure it behaves itself
(IOUtilsTestlet.java).
--Jeff
Index: src/java/org/apache/avalon/excalibur/io/IOUtil.java
===================================================================
RCS file:
/home/cvspublic/jakarta-avalon/src/java/org/apache/avalon/excalibur/io/IOUtil.java,v
retrieving revision 1.4
diff -u -r1.4 IOUtil.java
--- src/java/org/apache/avalon/excalibur/io/IOUtil.java 2001/06/24 12:09:57 1.4
+++ src/java/org/apache/avalon/excalibur/io/IOUtil.java 2001/07/04 09:30:42
@@ -7,19 +7,66 @@
*/
package org.apache.avalon.excalibur.io;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
-import java.io.InputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
import java.io.IOException;
-import java.io.OutputStream;
/**
- * This class provides basic facilities for manipulating io streams.
+ * General IO Stream manipulation.
+ * <p>
+ * This class provides static utility methods for input/output operations,
+particularly buffered
+ * copying between sources (<code>InputStream</code> and <code>Reader</code>,
+<code>String</code>)
+ * and destinations (<code>OutputStream</code>, <code>Writer</code> and
+<code>String</code>).
+ * </p>
+ *
+ * <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush
+or close the
+ * streams. Often, doing so would require making non-portable assumptions about the
+streams' origin
+ * and further use.</p>
+ *
+ * <p>For each <code>copy</code> method, a variant is provided that allows the caller
+to specify the
+ * buffer size (the default is 4k). As the buffer size can have a fairly large impact
+on speed, this
+ * may be worth tweaking. Often "large buffer -> faster" does not hold, even for
+large data
+ * transfers.</p>
+ *
+ * <p>For byte-to-char methods, a <code>copy</code> variant allows the encoding to be
+selected
+ * (otherwise the platform default is used).</p>
+ *
+ * <p>The <code>copy</code> methods use an internal buffer when copying. It is
+therefore advisable
+ * <em>not</em> to deliberately wrap the stream arguments to the <code>copy</code>
+methods in
+ * <code>Buffered*</code> streams. For example, don't do the
+ * following:</p>
+ *
+ * <code>copy( new BufferedInputStream( in ), new BufferedOutputStream( out )
+);</code>
*
+ * <p>The rationale is as follows:</p>
+ *
+ * <p>Imagine that an InputStream's read() is a very expensive operation, which would
+usually suggest
+ * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing
+infrequent
+ * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the
+underlying InputStream, to
+ * fill an internal buffer, from which further <code>read</code> requests can
+inexpensively get
+ * their data (until the buffer runs out).</p>
+ * <p>However, the <code>copy</code> methods do the same thing, keeping an internal
+buffer,
+ * populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having
+two buffers
+ * (or three if the destination stream is also buffered) is pointless, and the
+unnecessary buffer
+ * management hurts performance slightly (about 3%, according to some simple
+experiments).</p>
+ *
* @author <a href="mailto:[EMAIL PROTECTED]">Peter Donald</a>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jeff Turner</a>
*/
public final class IOUtil
{
+ private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
+
/**
* Private constructor to prevent instantiation.
*/
@@ -27,6 +74,11 @@
{
}
+ /**
+ * Unconditionally close an <code>OutputStream</code>.
+ * Equivalent to {@link OutputStream#close()}, except any exceptions will be
+ignored.
+ * @param output A (possibly null) OutputStream
+ */
public static void shutdownStream( final OutputStream output )
{
if( null == output )
@@ -38,6 +90,11 @@
catch( final IOException ioe ) {}
}
+ /**
+ * Unconditionally close an <code>InputStream</code>.
+ * Equivalent to {@link InputStream#close()}, except any exceptions will be
+ignored.
+ * @param input A (possibly null) InputStream
+ */
public static void shutdownStream( final InputStream input )
{
if( null == input )
@@ -49,47 +106,294 @@
catch( final IOException ioe ) {}
}
+ ///////////////////////////////////////////////////////////////
+ // Core copy methods
+///////////////////////////////////////////////////////////////
+
/**
- * Copy stream-data from source to destination. This method does not
- * buffer, flush or close the streams, as to do so would require making
- * non-portable assumptions about the streams' origin and further use. If
- * you wish to perform a buffered copy, use {@link #bufferedCopy}.
+ * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
*/
- public static void copy( final InputStream input, final OutputStream output )
+ public static OutputStream copy( final InputStream input, final OutputStream
+output )
throws IOException
- {
- final int BUFFER_SIZE = 1024 * 4;
- final byte[] buffer = new byte[ BUFFER_SIZE ];
+ {
+ return copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
- while( true )
+ /**
+ * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static OutputStream copy( final InputStream input, final OutputStream
+output, final int bufSize )
+ throws IOException
{
- final int count = input.read( buffer, 0, BUFFER_SIZE );
- if( -1 == count )
- {
- break;
- }
-
- // write out those same bytes
- output.write( buffer, 0, count );
+ final byte[] buffer = new byte[ bufSize ];
+ int n = 0;
+ while((n = input.read(buffer)) != -1)
+ output.write(buffer, 0, n);
+ return output;
}
- //needed to flush cache
- //output.flush();
- }
+ /**
+ * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+ */
+ public static Writer copy( final Reader input, final Writer output )
+ throws IOException
+ {
+ return copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
/**
- * Copy stream-data from source to destination, with buffering.
- * This is equivalent to passing {@link #copy} a {@link
- * java.io.BufferedInputStream} and {@link java.io.BufferedOutputStream} to
- * {@link #copy}, and flushing the output stream afterwards. The streams
- * are not closed after the copy.
+ * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
+ * @param bufSize Size of internal buffer to use.
*/
- public static void bufferedCopy( final InputStream source, final OutputStream
destination )
+ public static Writer copy( final Reader input, final Writer output, final int
+bufSize )
throws IOException
- {
- final BufferedInputStream input = new BufferedInputStream( source );
- final BufferedOutputStream output = new BufferedOutputStream( destination );
- copy( input, output );
- output.flush();
- }
+ {
+ final char[] buffer = new char[ bufSize ];
+ int n = 0;
+ while((n = input.read(buffer)) != -1)
+ output.write(buffer, 0, n);
+ return output;
+ }
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // InputStream -> *
+///////////////////////////////////////////////////////////////
+
+
+ ///////////////////////////////////////////////////////////////
+// InputStream -> Writer
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static Writer copy( final InputStream input, final Writer output )
+ throws IOException
+ {
+ return copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static Writer copy( final InputStream input, final Writer output, final
+int bufSize )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader(input);
+ return copy( in, output, bufSize );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ Charset Registry</a> for a list of valid encoding types.
+ */
+ public static Writer copy( final InputStream input, final Writer output, final
+String encoding )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader(input, encoding);
+ return copy( in, output );
+ }
+
+ /**
+ * Copy and convert bytes from an <code>InputStream</code> to chars on a
+ * <code>Writer</code>, using the specified encoding.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ Charset Registry</a> for a list of valid encoding types.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static Writer copy( final InputStream input, final Writer output, final
+String encoding,
+ final int bufSize )
+ throws IOException
+ {
+ final InputStreamReader in = new InputStreamReader(input, encoding);
+ return copy( in, output, bufSize );
+ }
+
+ ///////////////////////////////////////////////////////////////
+// InputStream -> String
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ */
+ public static String toString( final InputStream input )
+ throws IOException
+ {
+ return toString( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * The platform's default encoding is used for the byte-to-char conversion.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static String toString( final InputStream input, final int bufSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, bufSize );
+ return sw.toString();
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ Charset Registry</a> for a list of valid encoding types.
+ */
+ public static String toString( final InputStream input, final String encoding )
+ throws IOException
+ {
+ return toString( input, encoding, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of an <code>InputStream</code> as a String.
+ * @param encoding The name of a supported character encoding. See the
+ * <a href="http://www.iana.org/assignments/character-sets">IANA
+ Charset Registry</a> for a list of valid encoding types.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static String toString( final InputStream input, final String encoding,
+final int bufSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, encoding, bufSize );
+ return sw.toString();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+// String -> OutputStream
+
+ /**
+ * Serialize chars from a <code>String</code> to bytes on an
+<code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ */
+ public static OutputStream copy( final String input, final OutputStream output )
+ throws IOException
+ {
+ return copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Serialize chars from a <code>String</code> to bytes on an
+<code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static OutputStream copy( final String input, final OutputStream output,
+final int bufSize )
+ throws IOException
+ {
+ final StringReader in = new StringReader( input );
+ final OutputStreamWriter out = new OutputStreamWriter(output);
+ copy( in, out, bufSize );
+ // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we
+have to flush
+ // here.
+ out.flush();
+ return output;
+ }
+
+
+
+
+ ///////////////////////////////////////////////////////////////
+ // Derived copy methods
+ // Reader -> *
+///////////////////////////////////////////////////////////////
+
+ ///////////////////////////////////////////////////////////////
+// Reader -> OutputStream
+ /**
+ * Serialize chars from a <code>Reader</code> to bytes on an
+<code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ */
+ public static OutputStream copy( final Reader input, final OutputStream output )
+ throws IOException
+ {
+ return copy( input, output, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Serialize chars from a <code>Reader</code> to bytes on an
+<code>OutputStream</code>, and
+ * flush the <code>OutputStream</code>.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static OutputStream copy( final Reader input, final OutputStream output,
+final int bufSize )
+ throws IOException
+ {
+ final OutputStreamWriter out = new OutputStreamWriter(output);
+ copy( input, out, bufSize );
+ // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we
+have to flush
+ // here.
+ out.flush();
+ return output;
+ }
+
+ ///////////////////////////////////////////////////////////////
+// Reader -> String
+ /**
+ * Get the contents of a <code>Reader</code> as a String.
+ */
+ public static String toString( final Reader input )
+ throws IOException
+ {
+ return toString( input, DEFAULT_BUFFER_SIZE );
+ }
+
+ /**
+ * Get the contents of a <code>Reader</code> as a String.
+ * @param bufSize Size of internal buffer to use.
+ */
+ public static String toString( final Reader input, final int bufSize )
+ throws IOException
+ {
+ final StringWriter sw = new StringWriter();
+ copy( input, sw, bufSize );
+ return sw.toString();
+ }
+
+
+ ///////////////////////////////////////////////////////////////
+// String -> Writer
+
+ /**
+ * Copy chars from a <code>String</code> to a <code>Writer</code>.
+ */
+ public static Writer copy( final String input, final Writer output )
+ throws IOException
+ {
+ output.write( input );
+ return output;
+ }
+
+ /**
+ * Copy bytes from an <code>InputStream</code> to an
+ * <code>OutputStream</code>, with buffering.
+ * This is equivalent to passing a
+ * {@link java.io.BufferedInputStream} and
+ * {@link java.io.BufferedOuputStream} to {@link #copy(InputStream,
+OutputStream)},
+ * and flushing the output stream afterwards. The streams are not closed
+ * after the copy.
+ * @deprecated Buffering streams is actively harmful! See the class description
+as to why. Use
+ * {@link #copy(InputStream, OutputStream)} instead.
+ */
+ public static void bufferedCopy( final InputStream input, final OutputStream
+output )
+ throws IOException
+ {
+ final BufferedInputStream in = new BufferedInputStream( input );
+ final BufferedOutputStream out = new BufferedOutputStream( output );
+ copy( in, out );
+ out.flush();
+ }
+
}
Index: src/test/org/apache/avalon/excalibur/io/test/IOUtilTestlet.java
===================================================================
RCS file: IOUtilTestlet.java
diff -N IOUtilTestlet.java
--- /dev/null Wed Jul 4 02:27:00 2001
+++ IOUtilTestlet.java Wed Jul 4 02:31:06 2001
@@ -0,0 +1,341 @@
+/*
+ * Copyright The Apache Software Foundation. All rights reserved.
+ *
+ * This software is published under the terms of the Apache Software License
+ * version 1.1, a copy of which has been included with this distribution in
+ * the LICENSE file.
+ */
+package org.apache.avalon.excalibur.io.test;
+
+import java.io.*;
+import org.apache.avalon.excalibur.io.IOUtil;
+import org.apache.testlet.AbstractTestlet;
+import org.apache.testlet.TestFailedException;
+import java.util.Arrays; // Note: jdk1.2 dependency
+
+/**
+ * This is used to test IOUtil for correctness. The following checks are performed:
+ * <ul>
+ * <li>The return must not be null, must be the same type and equals() to the
+method's second arg</li>
+ * <li>All bytes must have been read from the source (available() == 0)</li>
+ * <li>The source and destination content must be identical (byte-wise comparison
+check)</li>
+ * <li>The output stream must not have been closed (a byte/char is written to test
+this, and
+ * subsequent size checked)</li>
+ * </ul>
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Jeff Turner</a>
+ */
+public final class IOUtilTestlet
+extends AbstractTestlet
+{
+ protected final int FILE_SIZE = 1024 * 4 + 1;
+
+ protected final File m_testDirectory;
+ protected final File m_testFile;
+
+ public IOUtilTestlet()
+ throws IOException
+ {
+ m_testDirectory = (new File( "test/io/" )).getAbsoluteFile();
+ if( !m_testDirectory.exists() )
+ {
+ m_testDirectory.mkdirs();
+ }
+
+ m_testFile = new File( m_testDirectory, "file2-test.txt" );
+
+ createFile( m_testFile, FILE_SIZE );
+ }
+
+ protected void createFile( final File file, final long size )
+ throws IOException
+ {
+ final BufferedOutputStream output =
+ new BufferedOutputStream( new FileOutputStream( file ) );
+
+ for( int i = 0; i < size; i++ )
+ {
+ output.write( (byte)(i % 255) ); // nice varied byte pattern
+ }
+
+ output.close();
+ }
+
+ /** Assert that the content of two files is the same. */
+ protected void assertEqualContent( final File f0, final File f1 )
+ throws IOException
+ {
+ FileInputStream is0 = new FileInputStream( f0 );
+ FileInputStream is1 = new FileInputStream( f1 );
+ final byte[] buf0 = new byte[ FILE_SIZE ];
+ final byte[] buf1 = new byte[ FILE_SIZE ];
+ int n0 = 0;
+ int n1 = 0;
+ while( n0 != -1 ) {
+ n0 = is0.read(buf0);
+ n1 = is1.read(buf1);
+ assert( "The files "+f0+" and "+f1+" have differing number of bytes
+available ("+n0+" vs "+n1+")", (n0 == n1) );
+ assert( "The files "+f0+" and "+f1+" have different content",
+Arrays.equals( buf0, buf1 ) );
+ }
+ }
+
+ public void testInputStreamToOutputStream()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileInputStream fin = new FileInputStream( m_testFile );
+ FileOutputStream fout = new FileOutputStream( destination );
+ FileOutputStream out = null;
+ try
+ {
+ out = (FileOutputStream) IOUtil.copy( fin, fout );
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ assert( "Not all bytes were read", fin.available() == 0 );
+ fout.flush();
+ assert( "The output file "+destination+" does not exist",
+destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintStream( out ).write( 0 );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ out.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+
+ public void testInputStreamToWriter()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileInputStream fin = new FileInputStream( m_testFile );
+ FileWriter fout = new FileWriter( destination );
+ FileWriter out = null;
+ try
+ {
+ out = (FileWriter) IOUtil.copy( fin, fout );
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ assert( "Not all bytes were read", fin.available() == 0 );
+ fout.flush();
+ assert( "Check existence of output file", destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintWriter( out ).print( 'a' );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ fout.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+
+ public void testInputStreamToString()
+ throws Exception
+ {
+ FileInputStream fin = new FileInputStream( m_testFile );
+ String out = null;
+ out = IOUtil.toString( fin );
+ assertNotNull( out );
+ assert( "Not all bytes were read", fin.available() == 0 );
+ assert( "Wrong output size: out.length()="+out.length()+"!="+FILE_SIZE,
+out.length() == FILE_SIZE );
+ }
+
+ ///////////////////////////////////////////////////////////
+ public void testReaderToOutputStream()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileReader fin = new FileReader( m_testFile );
+ FileOutputStream fout = new FileOutputStream( destination );
+ FileOutputStream out = null;
+ try
+ {
+ out = (FileOutputStream) IOUtil.copy( fin, fout );
+ //Note: this method *does* flush. It is equivalent to:
+ // final OutputStreamWriter _out = new OutputStreamWriter(fout);
+ // IOUtil.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
+ // _out.flush();
+ // out = fout;
+
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ // Note: rely on the method to flush
+ assert( "Check existence of output file", destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintStream( out ).write( 0 );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ out.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+
+ public void testReaderToWriter()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileReader fin = new FileReader( m_testFile );
+ FileWriter fout = new FileWriter( destination );
+ FileWriter out = null;
+ try
+ {
+ out = (FileWriter) IOUtil.copy( fin, fout );
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ fout.flush();
+ assert( "Check existence of output file", destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintWriter( out ).write( 'a' );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ out.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+
+ public void testReaderToString()
+ throws Exception
+ {
+ FileReader fin = new FileReader( m_testFile );
+ String out = null;
+ out = (String) IOUtil.toString( fin );
+ assertNotNull( out );
+ assert( "Wrong output size: out.length()="+out.length()+"!="+FILE_SIZE,
+out.length() == FILE_SIZE );
+ }
+
+ public void testStringToOutputStream()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileReader fin = new FileReader( m_testFile );
+ String str;
+ // Create our String. Rely on testReaderToString() to make sure this is
+valid.
+ str = IOUtil.toString(fin);
+ FileOutputStream fout = new FileOutputStream( destination );
+ FileOutputStream out = null;
+ try
+ {
+ out = (FileOutputStream) IOUtil.copy( str, fout );
+ //Note: this method *does* flush. It is equivalent to:
+ // final OutputStreamWriter _out = new OutputStreamWriter(fout);
+ // IOUtil.copy( str, _out, 4096 ); // copy( Reader, Writer, int );
+ // _out.flush();
+ // out = fout;
+
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ // note: we don't flush here; this IOUtils method does it for us
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ assert( "Check existence of output file", destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintStream( out ).write( 0 );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ out.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+
+
+ public void testStringToWriter()
+ throws Exception
+ {
+ final File destination = new File( m_testDirectory, "copy.txt" );
+ assert( "Test output data file shouldn't previously exist",
+!destination.exists() );
+ FileReader fin = new FileReader( m_testFile );
+ String str;
+ // Create our String. Rely on testReaderToString() to make sure this is
+valid.
+ str = IOUtil.toString(fin);
+ FileWriter fout = new FileWriter( destination );
+ FileWriter out = null;
+ try
+ {
+ out = (FileWriter) IOUtil.copy( str, fout );
+
+ } catch ( ClassCastException e )
+ {
+ throw new TestFailedException( "The copy() method didn't return an
+object of same"
+ +"type as it's second input" + e.getMessage() );
+ }
+ assertNotNull( out );
+ assertEquality( "copy() must return it's second arg", fout, out );
+ fout.flush();
+ assert( "Check existence of output file", destination.exists() );
+ assertEqualContent( m_testFile, destination );
+ try
+ {
+ new PrintWriter( out ).print( 'a' );
+ }
+ catch (Throwable t)
+ {
+ throw new TestFailedException( "The copy() method closed the stream
+when it shouldn't"
+ +" have. " + t.getMessage() );
+ }
+ out.close();
+ assert( "Wrong output size:
+destination.length()="+destination.length()+"!="+FILE_SIZE+1,
+ destination.length() == FILE_SIZE+1 );
+ destination.delete();
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]