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]

Reply via email to