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 -> 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 }