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