View Javadoc
1   package org.codehaus.plexus.util;
2   
3   /* ====================================================================
4    * The Apache Software License, Version 1.1
5    *
6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
7    * reserved.
8    *
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   * 1. Redistributions of source code must retain the above copyright
14   *    notice, this list of conditions and the following disclaimer.
15   *
16   * 2. Redistributions in binary form must reproduce the above copyright
17   *    notice, this list of conditions and the following disclaimer in
18   *    the documentation and/or other materials provided with the
19   *    distribution.
20   *
21   * 3. The end-user documentation included with the redistribution,
22   *    if any, must include the following acknowledgment:
23   *       "This product includes software developed by the
24   *        Apache Software Foundation (http://www.codehaus.org/)."
25   *    Alternately, this acknowledgment may appear in the software itself,
26   *    if and wherever such third-party acknowledgments normally appear.
27   *
28   * 4. The names "Apache" and "Apache Software Foundation" and
29   *    "Apache Turbine" must not be used to endorse or promote products
30   *    derived from this software without prior written permission. For
31   *    written permission, please contact codehaus@codehaus.org.
32   *
33   * 5. Products derived from this software may not be called "Apache",
34   *    "Apache Turbine", nor may "Apache" appear in their name, without
35   *    prior written permission of the Apache Software Foundation.
36   *
37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48   * SUCH DAMAGE.
49   * ====================================================================
50   *
51   * This software consists of voluntary contributions made by many
52   * individuals on behalf of the Apache Software Foundation.  For more
53   * information on the Apache Software Foundation, please see
54   * <http://www.codehaus.org/>.
55   */
56  
57  import java.io.BufferedInputStream;
58  import java.io.BufferedOutputStream;
59  import java.io.ByteArrayInputStream;
60  import java.io.ByteArrayOutputStream;
61  import java.io.IOException;
62  import java.io.InputStream;
63  import java.io.InputStreamReader;
64  import java.io.OutputStream;
65  import java.io.OutputStreamWriter;
66  import java.io.Reader;
67  import java.io.StringReader;
68  import java.io.StringWriter;
69  import java.io.Writer;
70  import java.nio.channels.Channel;
71  
72  /**
73   * General IO Stream manipulation.
74   * <p>
75   * This class provides static utility methods for input/output operations, particularly buffered
76   * copying between sources (<code>InputStream</code>, <code>Reader</code>, <code>String</code> and
77   * <code>byte[]</code>) and destinations (<code>OutputStream</code>, <code>Writer</code>,
78   * <code>String</code> and <code>byte[]</code>).
79   * </p>
80   *
81   * <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush or close the
82   * streams. Often, doing so would require making non-portable assumptions about the streams' origin
83   * and further use. This means that both streams' <code>close()</code> methods must be called after
84   * copying. if one omits this step, then the stream resources (sockets, file descriptors) are
85   * released when the associated Stream is garbage-collected. It is not a good idea to rely on this
86   * mechanism. For a good overview of the distinction between "memory management" and "resource
87   * management", see <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
88   * UnixReview article</a></p>
89   *
90   * <p>For each <code>copy</code> method, a variant is provided that allows the caller to specify the
91   * buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this
92   * may be worth tweaking. Often "large buffer -&gt; faster" does not hold, even for large data
93   * transfers.</p>
94   *
95   * <p>For byte-to-char methods, a <code>copy</code> variant allows the encoding to be selected
96   * (otherwise the platform default is used).</p>
97   *
98   * <p>The <code>copy</code> methods use an internal buffer when copying. It is therefore advisable
99   * <em>not</em> to deliberately wrap the stream arguments to the <code>copy</code> methods in
100  * <code>Buffered*</code> streams. For example, don't do the
101  * following:</p>
102  *
103  * <code>copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );</code>
104  *
105  * <p>The rationale is as follows:</p>
106  *
107  * <p>Imagine that an InputStream's read() is a very expensive operation, which would usually suggest
108  * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent
109  * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to
110  * fill an internal buffer, from which further <code>read</code> requests can inexpensively get
111  * their data (until the buffer runs out).</p>
112  * <p>However, the <code>copy</code> methods do the same thing, keeping an internal buffer,
113  * populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having two buffers
114  * (or three if the destination stream is also buffered) is pointless, and the unnecessary buffer
115  * management hurts performance slightly (about 3%, according to some simple experiments).</p>
116  *
117  * @author <a href="mailto:peter@codehaus.org">Peter Donald</a>
118  * @author <a href="mailto:jefft@codehaus.org">Jeff Turner</a>
119  * @version $Id$
120  * @since 4.0
121  */
122 
123 /*
124  * Behold, intrepid explorers; a map of this class:
125  *
126  *       Method      Input               Output          Dependency
127  *       ------      -----               ------          -------
128  * 1     copy        InputStream         OutputStream    (primitive)
129  * 2     copy        Reader              Writer          (primitive)
130  *
131  * 3     copy        InputStream         Writer          2
132  * 4     toString    InputStream         String          3
133  * 5     toByteArray InputStream         byte[]          1
134  *
135  * 6     copy        Reader              OutputStream    2
136  * 7     toString    Reader              String          2
137  * 8     toByteArray Reader              byte[]          6
138  *
139  * 9     copy        String              OutputStream    2
140  * 10    copy        String              Writer          (trivial)
141  * 11    toByteArray String              byte[]          9
142  *
143  * 12    copy        byte[]              Writer          3
144  * 13    toString    byte[]              String          12
145  * 14    copy        byte[]              OutputStream    (trivial)
146  *
147  *
148  * Note that only the first two methods shuffle bytes; the rest use these two, or (if possible) copy
149  * using native Java copy methods. As there are method variants to specify buffer size and encoding,
150  * each row may correspond to up to 4 methods.
151  *
152  */
153 
154 public final class IOUtil
155 {
156     private static final int DEFAULT_BUFFER_SIZE = 1024 * 16;
157 
158     /**
159      * Private constructor to prevent instantiation.
160      */
161     private IOUtil()
162     {
163     }
164 
165     ///////////////////////////////////////////////////////////////
166     // Core copy methods
167     ///////////////////////////////////////////////////////////////
168 
169     /**
170      * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
171      */
172     public static void copy( final InputStream input, final OutputStream output )
173         throws IOException
174     {
175         copy( input, output, DEFAULT_BUFFER_SIZE );
176     }
177 
178     /**
179      * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
180      * @param bufferSize Size of internal buffer to use.
181      */
182     public static void copy( final InputStream input,
183                              final OutputStream output,
184                              final int bufferSize )
185         throws IOException
186     {
187         final byte[] buffer = new byte[bufferSize];
188         int n = 0;
189         while ( 0 <= ( n = input.read( buffer ) ) )
190         {
191             output.write( buffer, 0, n );
192         }
193     }
194 
195     /**
196      * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
197      */
198     public static void copy( final Reader input, final Writer output )
199         throws IOException
200     {
201         copy( input, output, DEFAULT_BUFFER_SIZE );
202     }
203 
204     /**
205      * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
206      * @param bufferSize Size of internal buffer to use.
207      */
208     public static void copy( final Reader input, final Writer output, final int bufferSize )
209         throws IOException
210     {
211         final char[] buffer = new char[bufferSize];
212         int n = 0;
213         while ( 0 <= ( n = input.read( buffer ) ) )
214         {
215             output.write( buffer, 0, n );
216         }
217         output.flush();
218     }
219 
220     ///////////////////////////////////////////////////////////////
221     // Derived copy methods
222     // InputStream -> *
223     ///////////////////////////////////////////////////////////////
224 
225 
226     ///////////////////////////////////////////////////////////////
227     // InputStream -> Writer
228 
229     /**
230      * Copy and convert bytes from an <code>InputStream</code> to chars on a
231      * <code>Writer</code>.
232      * The platform's default encoding is used for the byte-to-char conversion.
233      */
234     public static void copy( final InputStream input, final Writer output )
235         throws IOException
236     {
237         copy( input, output, DEFAULT_BUFFER_SIZE );
238     }
239 
240     /**
241      * Copy and convert bytes from an <code>InputStream</code> to chars on a
242      * <code>Writer</code>.
243      * The platform's default encoding is used for the byte-to-char conversion.
244      * @param bufferSize Size of internal buffer to use.
245      */
246     public static void copy( final InputStream input, final Writer output, final int bufferSize )
247         throws IOException
248     {
249         final InputStreamReader in = new InputStreamReader( input );
250         copy( in, output, bufferSize );
251     }
252 
253     /**
254      * Copy and convert bytes from an <code>InputStream</code> to chars on a
255      * <code>Writer</code>, using the specified encoding.
256      * @param encoding The name of a supported character encoding. See the
257      * <a href="http://www.iana.org/assignments/character-sets">IANA
258      * Charset Registry</a> for a list of valid encoding types.
259      */
260     public static void copy( final InputStream input, final Writer output, final String encoding )
261         throws IOException
262     {
263         final InputStreamReader in = new InputStreamReader( input, encoding );
264         copy( in, output );
265     }
266 
267     /**
268      * Copy and convert bytes from an <code>InputStream</code> to chars on a
269      * <code>Writer</code>, using the specified encoding.
270      * @param encoding The name of a supported character encoding. See the
271      *        <a href="http://www.iana.org/assignments/character-sets">IANA
272      *        Charset Registry</a> for a list of valid encoding types.
273      * @param bufferSize Size of internal buffer to use.
274      */
275     public static void copy( final InputStream input,
276                              final Writer output,
277                              final String encoding,
278                              final int bufferSize )
279         throws IOException
280     {
281         final InputStreamReader in = new InputStreamReader( input, encoding );
282         copy( in, output, bufferSize );
283     }
284 
285 
286     ///////////////////////////////////////////////////////////////
287     // InputStream -> String
288 
289     /**
290      * Get the contents of an <code>InputStream</code> as a String.
291      * The platform's default encoding is used for the byte-to-char conversion.
292      */
293     public static String toString( final InputStream input )
294         throws IOException
295     {
296         return toString( input, DEFAULT_BUFFER_SIZE );
297     }
298 
299     /**
300      * Get the contents of an <code>InputStream</code> as a String.
301      * The platform's default encoding is used for the byte-to-char conversion.
302      * @param bufferSize Size of internal buffer to use.
303      */
304     public static String toString( final InputStream input, final int bufferSize )
305         throws IOException
306     {
307         final StringWriter sw = new StringWriter();
308         copy( input, sw, bufferSize );
309         return sw.toString();
310     }
311 
312     /**
313      * Get the contents of an <code>InputStream</code> as a String.
314      * @param encoding The name of a supported character encoding. See the
315      *    <a href="http://www.iana.org/assignments/character-sets">IANA
316      *    Charset Registry</a> for a list of valid encoding types.
317      */
318     public static String toString( final InputStream input, final String encoding )
319         throws IOException
320     {
321         return toString( input, encoding, DEFAULT_BUFFER_SIZE );
322     }
323 
324     /**
325      * Get the contents of an <code>InputStream</code> as a String.
326      * @param encoding The name of a supported character encoding. See the
327      *   <a href="http://www.iana.org/assignments/character-sets">IANA
328      *   Charset Registry</a> for a list of valid encoding types.
329      * @param bufferSize Size of internal buffer to use.
330      */
331     public static String toString( final InputStream input,
332                                    final String encoding,
333                                    final int bufferSize )
334         throws IOException
335     {
336         final StringWriter sw = new StringWriter();
337         copy( input, sw, encoding, bufferSize );
338         return sw.toString();
339     }
340 
341     ///////////////////////////////////////////////////////////////
342     // InputStream -> byte[]
343 
344     /**
345      * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
346      */
347     public static byte[] toByteArray( final InputStream input )
348         throws IOException
349     {
350         return toByteArray( input, DEFAULT_BUFFER_SIZE );
351     }
352 
353     /**
354      * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
355      * @param bufferSize Size of internal buffer to use.
356      */
357     public static byte[] toByteArray( final InputStream input, final int bufferSize )
358         throws IOException
359     {
360         final ByteArrayOutputStream output = new ByteArrayOutputStream();
361         copy( input, output, bufferSize );
362         return output.toByteArray();
363     }
364 
365 
366     ///////////////////////////////////////////////////////////////
367     // Derived copy methods
368     // Reader -> *
369     ///////////////////////////////////////////////////////////////
370 
371     ///////////////////////////////////////////////////////////////
372     // Reader -> OutputStream
373     /**
374      * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
375      * flush the <code>OutputStream</code>.
376      */
377     public static void copy( final Reader input, final OutputStream output )
378         throws IOException
379     {
380         copy( input, output, DEFAULT_BUFFER_SIZE );
381     }
382 
383     /**
384      * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
385      * flush the <code>OutputStream</code>.
386      * @param bufferSize Size of internal buffer to use.
387      */
388     public static void copy( final Reader input, final OutputStream output, final int bufferSize )
389         throws IOException
390     {
391         final OutputStreamWriter out = new OutputStreamWriter( output );
392         copy( input, out, bufferSize );
393         // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
394         // here.
395         out.flush();
396     }
397 
398     ///////////////////////////////////////////////////////////////
399     // Reader -> String
400     /**
401      * Get the contents of a <code>Reader</code> as a String.
402      */
403     public static String toString( final Reader input )
404         throws IOException
405     {
406         return toString( input, DEFAULT_BUFFER_SIZE );
407     }
408 
409     /**
410      * Get the contents of a <code>Reader</code> as a String.
411      * @param bufferSize Size of internal buffer to use.
412      */
413     public static String toString( final Reader input, final int bufferSize )
414         throws IOException
415     {
416         final StringWriter sw = new StringWriter();
417         copy( input, sw, bufferSize );
418         return sw.toString();
419     }
420 
421 
422     ///////////////////////////////////////////////////////////////
423     // Reader -> byte[]
424     /**
425      * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
426      */
427     public static byte[] toByteArray( final Reader input )
428         throws IOException
429     {
430         return toByteArray( input, DEFAULT_BUFFER_SIZE );
431     }
432 
433     /**
434      * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
435      * @param bufferSize Size of internal buffer to use.
436      */
437     public static byte[] toByteArray( final Reader input, final int bufferSize )
438         throws IOException
439     {
440         ByteArrayOutputStream output = new ByteArrayOutputStream();
441         copy( input, output, bufferSize );
442         return output.toByteArray();
443     }
444 
445 
446     ///////////////////////////////////////////////////////////////
447     // Derived copy methods
448     // String -> *
449     ///////////////////////////////////////////////////////////////
450 
451 
452     ///////////////////////////////////////////////////////////////
453     // String -> OutputStream
454 
455     /**
456      * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
457      * flush the <code>OutputStream</code>.
458      */
459     public static void copy( final String input, final OutputStream output )
460         throws IOException
461     {
462         copy( input, output, DEFAULT_BUFFER_SIZE );
463     }
464 
465     /**
466      * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
467      * flush the <code>OutputStream</code>.
468      * @param bufferSize Size of internal buffer to use.
469      */
470     public static void copy( final String input, final OutputStream output, final int bufferSize )
471         throws IOException
472     {
473         final StringReader in = new StringReader( input );
474         final OutputStreamWriter out = new OutputStreamWriter( output );
475         copy( in, out, bufferSize );
476         // NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
477         // here.
478         out.flush();
479     }
480 
481 
482 
483     ///////////////////////////////////////////////////////////////
484     // String -> Writer
485 
486     /**
487      * Copy chars from a <code>String</code> to a <code>Writer</code>.
488      */
489     public static void copy( final String input, final Writer output )
490         throws IOException
491     {
492         output.write( input );
493     }
494 
495     /**
496      * Copy bytes from an <code>InputStream</code> to an
497      * <code>OutputStream</code>, with buffering.
498      * This is equivalent to passing a
499      * {@link java.io.BufferedInputStream} and
500      * {@link java.io.BufferedOutputStream} to {@link #copy(InputStream, OutputStream)},
501      * and flushing the output stream afterwards. The streams are not closed
502      * after the copy.
503      * @deprecated Buffering streams is actively harmful! See the class description as to why. Use
504      * {@link #copy(InputStream, OutputStream)} instead.
505      */
506     public static void bufferedCopy( final InputStream input, final OutputStream output )
507         throws IOException
508     {
509         final BufferedInputStream in = new BufferedInputStream( input );
510         final BufferedOutputStream out = new BufferedOutputStream( output );
511         copy( in, out );
512         out.flush();
513     }
514 
515 
516     ///////////////////////////////////////////////////////////////
517     // String -> byte[]
518     /**
519      * Get the contents of a <code>String</code> as a <code>byte[]</code>.
520      */
521     public static byte[] toByteArray( final String input )
522         throws IOException
523     {
524         return toByteArray( input, DEFAULT_BUFFER_SIZE );
525     }
526 
527     /**
528      * Get the contents of a <code>String</code> as a <code>byte[]</code>.
529      * @param bufferSize Size of internal buffer to use.
530      */
531     public static byte[] toByteArray( final String input, final int bufferSize )
532         throws IOException
533     {
534         ByteArrayOutputStream output = new ByteArrayOutputStream();
535         copy( input, output, bufferSize );
536         return output.toByteArray();
537     }
538 
539 
540 
541     ///////////////////////////////////////////////////////////////
542     // Derived copy methods
543     // byte[] -> *
544     ///////////////////////////////////////////////////////////////
545 
546 
547     ///////////////////////////////////////////////////////////////
548     // byte[] -> Writer
549 
550     /**
551      * Copy and convert bytes from a <code>byte[]</code> to chars on a
552      * <code>Writer</code>.
553      * The platform's default encoding is used for the byte-to-char conversion.
554      */
555     public static void copy( final byte[] input, final Writer output )
556         throws IOException
557     {
558         copy( input, output, DEFAULT_BUFFER_SIZE );
559     }
560 
561     /**
562      * Copy and convert bytes from a <code>byte[]</code> to chars on a
563      * <code>Writer</code>.
564      * The platform's default encoding is used for the byte-to-char conversion.
565      * @param bufferSize Size of internal buffer to use.
566      */
567     public static void copy( final byte[] input, final Writer output, final int bufferSize )
568         throws IOException
569     {
570         final ByteArrayInputStream in = new ByteArrayInputStream( input );
571         copy( in, output, bufferSize );
572     }
573 
574     /**
575      * Copy and convert bytes from a <code>byte[]</code> to chars on a
576      * <code>Writer</code>, using the specified encoding.
577      * @param encoding The name of a supported character encoding. See the
578      * <a href="http://www.iana.org/assignments/character-sets">IANA
579      * Charset Registry</a> for a list of valid encoding types.
580      */
581     public static void copy( final byte[] input, final Writer output, final String encoding )
582         throws IOException
583     {
584         final ByteArrayInputStream in = new ByteArrayInputStream( input );
585         copy( in, output, encoding );
586     }
587 
588     /**
589      * Copy and convert bytes from a <code>byte[]</code> to chars on a
590      * <code>Writer</code>, using the specified encoding.
591      * @param encoding The name of a supported character encoding. See the
592      *        <a href="http://www.iana.org/assignments/character-sets">IANA
593      *        Charset Registry</a> for a list of valid encoding types.
594      * @param bufferSize Size of internal buffer to use.
595      */
596     public static void copy( final byte[] input,
597                              final Writer output,
598                              final String encoding,
599                              final int bufferSize )
600         throws IOException
601     {
602         final ByteArrayInputStream in = new ByteArrayInputStream( input );
603         copy( in, output, encoding, bufferSize );
604     }
605 
606 
607     ///////////////////////////////////////////////////////////////
608     // byte[] -> String
609 
610     /**
611      * Get the contents of a <code>byte[]</code> as a String.
612      * The platform's default encoding is used for the byte-to-char conversion.
613      */
614     public static String toString( final byte[] input )
615         throws IOException
616     {
617         return toString( input, DEFAULT_BUFFER_SIZE );
618     }
619 
620     /**
621      * Get the contents of a <code>byte[]</code> as a String.
622      * The platform's default encoding is used for the byte-to-char conversion.
623      * @param bufferSize Size of internal buffer to use.
624      */
625     public static String toString( final byte[] input, final int bufferSize )
626         throws IOException
627     {
628         final StringWriter sw = new StringWriter();
629         copy( input, sw, bufferSize );
630         return sw.toString();
631     }
632 
633     /**
634      * Get the contents of a <code>byte[]</code> as a String.
635      * @param encoding The name of a supported character encoding. See the
636      *    <a href="http://www.iana.org/assignments/character-sets">IANA
637      *    Charset Registry</a> for a list of valid encoding types.
638      */
639     public static String toString( final byte[] input, final String encoding )
640         throws IOException
641     {
642         return toString( input, encoding, DEFAULT_BUFFER_SIZE );
643     }
644 
645     /**
646      * Get the contents of a <code>byte[]</code> as a String.
647      * @param encoding The name of a supported character encoding. See the
648      *   <a href="http://www.iana.org/assignments/character-sets">IANA
649      *   Charset Registry</a> for a list of valid encoding types.
650      * @param bufferSize Size of internal buffer to use.
651      */
652     public static String toString( final byte[] input,
653                                    final String encoding,
654                                    final int bufferSize )
655         throws IOException
656     {
657         final StringWriter sw = new StringWriter();
658         copy( input, sw, encoding, bufferSize );
659         return sw.toString();
660     }
661 
662 
663     ///////////////////////////////////////////////////////////////
664     // byte[] -> OutputStream
665 
666     /**
667      * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
668      */
669     public static void copy( final byte[] input, final OutputStream output )
670         throws IOException
671     {
672         copy( input, output, DEFAULT_BUFFER_SIZE );
673     }
674 
675     /**
676      * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
677      * @param bufferSize Size of internal buffer to use.
678      */
679     public static void copy( final byte[] input,
680                              final OutputStream output,
681                              final int bufferSize )
682         throws IOException
683     {
684         output.write( input );
685     }
686 
687     /**
688      * Compare the contents of two Streams to determine if they are equal or not.
689      *
690      * @param input1 the first stream
691      * @param input2 the second stream
692      * @return true if the content of the streams are equal or they both don't exist, false otherwise
693      */
694     public static boolean contentEquals( final InputStream input1,
695                                          final InputStream input2 )
696         throws IOException
697     {
698         final InputStream bufferedInput1 = new BufferedInputStream( input1 );
699         final InputStream bufferedInput2 = new BufferedInputStream( input2 );
700 
701         int ch = bufferedInput1.read();
702         while ( 0 <= ch )
703         {
704             final int ch2 = bufferedInput2.read();
705             if ( ch != ch2 )
706             {
707                 return false;
708             }
709             ch = bufferedInput1.read();
710         }
711 
712         final int ch2 = bufferedInput2.read();
713         if ( 0 <= ch2 )
714         {
715             return false;
716         }
717         else
718         {
719             return true;
720         }
721     }
722 
723     // ----------------------------------------------------------------------
724     // closeXXX()
725     // ----------------------------------------------------------------------
726 
727     /**
728      * Closes the input stream. The input stream can be null and any IOException's will be swallowed.
729      * 
730      * @param inputStream The stream to close.
731      */
732     public static void close( InputStream inputStream )
733     {
734         if ( inputStream == null )
735         {
736             return;
737         }
738 
739         try
740         {
741             inputStream.close();
742         }
743         catch( IOException ex )
744         {
745             // ignore
746         }
747     }
748 
749     /**
750      * Closes a channel. Channel can be null and any IOException's will be swallowed.
751      *
752      * @param channel The stream to close.
753      */
754     public static void close( Channel channel )
755     {
756         if ( channel == null )
757         {
758             return;
759         }
760 
761         try
762         {
763             channel.close();
764         }
765         catch( IOException ex )
766         {
767             // ignore
768         }
769     }
770 
771     /**
772      * Closes the output stream. The output stream can be null and any IOException's will be swallowed.
773      * 
774      * @param outputStream The stream to close.
775      */
776     public static void close( OutputStream outputStream )
777     {
778         if ( outputStream == null )
779         {
780             return;
781         }
782 
783         try
784         {
785             outputStream.close();
786         }
787         catch( IOException ex )
788         {
789             // ignore
790         }
791     }
792 
793     /**
794      * Closes the reader. The reader can be null and any IOException's will be swallowed.
795      * 
796      * @param reader The reader to close.
797      */
798     public static void close( Reader reader )
799     {
800         if ( reader == null )
801         {
802             return;
803         }
804 
805         try
806         {
807             reader.close();
808         }
809         catch( IOException ex )
810         {
811             // ignore
812         }
813     }
814 
815     /**
816      * Closes the writer. The writer can be null and any IOException's will be swallowed.
817      * 
818      * @param writer The writer to close.
819      */
820     public static void close( Writer writer )
821     {
822         if ( writer == null )
823         {
824             return;
825         }
826 
827         try
828         {
829             writer.close();
830         }
831         catch( IOException ex )
832         {
833             // ignore
834         }
835     }
836 }