1 /*****************************************************************
2 * Licensed to the Apache Software Foundation (ASF) under one *
3 * or more contributor license agreements. See the NOTICE file *
4 * distributed with this work for additional information *
5 * regarding copyright ownership. The ASF licenses this file *
6 * to you under the Apache License, Version 2.0 (the *
7 * "License"); you may not use this file except in compliance *
8 * with the License. You may obtain a copy of the License at *
9 * *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, *
13 * software distributed under the License is distributed on an *
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15 * KIND, either express or implied. See the License for the *
16 * specific language governing permissions and limitations *
17 * under the License. *
18 ****************************************************************/
19
20 package org.apache.james.util.io;
21
22 import java.io.BufferedInputStream;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.OutputStream;
29 import java.io.OutputStreamWriter;
30 import java.io.Reader;
31 import java.io.StringReader;
32 import java.io.StringWriter;
33 import java.io.Writer;
34
35 /***
36 * General IO Stream manipulation.
37 * <p>
38 * This class provides static utility methods for input/output operations, particularly buffered
39 * copying between sources (<code>InputStream</code>, <code>Reader</code>, <code>String</code> and
40 * <code>byte[]</code>) and destinations (<code>OutputStream</code>, <code>Writer</code>,
41 * <code>String</code> and <code>byte[]</code>).
42 * </p>
43 *
44 * <p>Unless otherwise noted, these <code>copy</code> methods do <em>not</em> flush or close the
45 * streams. Often, doing so would require making non-portable assumptions about the streams' origin
46 * and further use. This means that both streams' <code>close()</code> methods must be called after
47 * copying. if one omits this step, then the stream resources (sockets, file descriptors) are
48 * released when the associated Stream is garbage-collected. It is not a good idea to rely on this
49 * mechanism. For a good overview of the distinction between "memory management" and "resource
50 * management", see <a href="http://www.unixreview.com/articles/1998/9804/9804ja/ja.htm">this
51 * UnixReview article</a></p>
52 *
53 * <p>For each <code>copy</code> method, a variant is provided that allows the caller to specify the
54 * buffer size (the default is 4k). As the buffer size can have a fairly large impact on speed, this
55 * may be worth tweaking. Often "large buffer -> faster" does not hold, even for large data
56 * transfers.</p>
57 *
58 * <p>For byte-to-char methods, a <code>copy</code> variant allows the encoding to be selected
59 * (otherwise the platform default is used).</p>
60 *
61 * <p>The <code>copy</code> methods use an internal buffer when copying. It is therefore advisable
62 * <em>not</em> to deliberately wrap the stream arguments to the <code>copy</code> methods in
63 * <code>Buffered*</code> streams. For example, don't do the
64 * following:</p>
65 *
66 * <code>copy( new BufferedInputStream( in ), new BufferedOutputStream( out ) );</code>
67 *
68 * <p>The rationale is as follows:</p>
69 *
70 * <p>Imagine that an InputStream's read() is a very expensive operation, which would usually suggest
71 * wrapping in a BufferedInputStream. The BufferedInputStream works by issuing infrequent
72 * {@link java.io.InputStream#read(byte[] b, int off, int len)} requests on the underlying InputStream, to
73 * fill an internal buffer, from which further <code>read</code> requests can inexpensively get
74 * their data (until the buffer runs out).</p>
75 * <p>However, the <code>copy</code> methods do the same thing, keeping an internal buffer,
76 * populated by {@link InputStream#read(byte[] b, int off, int len)} requests. Having two buffers
77 * (or three if the destination stream is also buffered) is pointless, and the unnecessary buffer
78 * management hurts performance slightly (about 3%, according to some simple experiments).</p>
79 *
80 * @author Peter Donald
81 * @author <a href="mailto:jefft@apache.org">Jeff Turner</a>
82 * @version CVS $Revision: 494012 $ $Date: 2007-01-08 10:23:58 +0000 (Mon, 08 Jan 2007) $
83 * @since 4.0
84 */
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117 public final class IOUtil
118 {
119 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
120
121 /***
122 * Private constructor to prevent instantiation.
123 */
124 private IOUtil()
125 {
126 }
127
128 /***
129 * Unconditionally close an <code>Reader</code>.
130 * Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
131 *
132 * @param input A (possibly null) Reader
133 */
134 public static void shutdownReader( final Reader input )
135 {
136 if( null == input )
137 {
138 return;
139 }
140
141 try
142 {
143 input.close();
144 }
145 catch( final IOException ioe )
146 {
147 }
148 }
149
150 /***
151 * Unconditionally close an <code>Writer</code>.
152 * Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
153 *
154 * @param output A (possibly null) Writer
155 */
156 public static void shutdownWriter( final Writer output )
157 {
158 if( null == output )
159 {
160 return;
161 }
162
163 try
164 {
165 output.close();
166 }
167 catch( final IOException ioe )
168 {
169 }
170 }
171
172 /***
173 * Unconditionally close an <code>OutputStream</code>.
174 * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
175 * @param output A (possibly null) OutputStream
176 */
177 public static void shutdownStream( final OutputStream output )
178 {
179 if( null == output )
180 {
181 return;
182 }
183
184 try
185 {
186 output.close();
187 }
188 catch( final IOException ioe )
189 {
190 }
191 }
192
193 /***
194 * Unconditionally close an <code>InputStream</code>.
195 * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
196 * @param input A (possibly null) InputStream
197 */
198 public static void shutdownStream( final InputStream input )
199 {
200 if( null == input )
201 {
202 return;
203 }
204
205 try
206 {
207 input.close();
208 }
209 catch( final IOException ioe )
210 {
211 }
212 }
213
214
215
216
217
218 /***
219 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
220 */
221 public static void copy( final InputStream input, final OutputStream output )
222 throws IOException
223 {
224 copy( input, output, DEFAULT_BUFFER_SIZE );
225 }
226
227 /***
228 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
229 * @param bufferSize Size of internal buffer to use.
230 */
231 public static void copy( final InputStream input,
232 final OutputStream output,
233 final int bufferSize )
234 throws IOException
235 {
236 final byte[] buffer = new byte[ bufferSize ];
237 int n = 0;
238 while( -1 != ( n = input.read( buffer ) ) )
239 {
240 output.write( buffer, 0, n );
241 }
242 }
243
244 /***
245 * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
246 */
247 public static void copy( final Reader input, final Writer output )
248 throws IOException
249 {
250 copy( input, output, DEFAULT_BUFFER_SIZE );
251 }
252
253 /***
254 * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
255 * @param bufferSize Size of internal buffer to use.
256 */
257 public static void copy( final Reader input, final Writer output, final int bufferSize )
258 throws IOException
259 {
260 final char[] buffer = new char[ bufferSize ];
261 int n = 0;
262 while( -1 != ( n = input.read( buffer ) ) )
263 {
264 output.write( buffer, 0, n );
265 }
266 }
267
268
269
270
271
272
273
274
275
276
277 /***
278 * Copy and convert bytes from an <code>InputStream</code> to chars on a
279 * <code>Writer</code>.
280 * The platform's default encoding is used for the byte-to-char conversion.
281 */
282 public static void copy( final InputStream input, final Writer output )
283 throws IOException
284 {
285 copy( input, output, DEFAULT_BUFFER_SIZE );
286 }
287
288 /***
289 * Copy and convert bytes from an <code>InputStream</code> to chars on a
290 * <code>Writer</code>.
291 * The platform's default encoding is used for the byte-to-char conversion.
292 * @param bufferSize Size of internal buffer to use.
293 */
294 public static void copy( final InputStream input, final Writer output, final int bufferSize )
295 throws IOException
296 {
297 final InputStreamReader in = new InputStreamReader( input );
298 copy( in, output, bufferSize );
299 }
300
301 /***
302 * Copy and convert bytes from an <code>InputStream</code> to chars on a
303 * <code>Writer</code>, using the specified encoding.
304 * @param encoding The name of a supported character encoding. See the
305 * <a href="http://www.iana.org/assignments/character-sets">IANA
306 * Charset Registry</a> for a list of valid encoding types.
307 */
308 public static void copy( final InputStream input, final Writer output, final String encoding )
309 throws IOException
310 {
311 final InputStreamReader in = new InputStreamReader( input, encoding );
312 copy( in, output );
313 }
314
315 /***
316 * Copy and convert bytes from an <code>InputStream</code> to chars on a
317 * <code>Writer</code>, using the specified encoding.
318 * @param encoding The name of a supported character encoding. See the
319 * <a href="http://www.iana.org/assignments/character-sets">IANA
320 * Charset Registry</a> for a list of valid encoding types.
321 * @param bufferSize Size of internal buffer to use.
322 */
323 public static void copy( final InputStream input,
324 final Writer output,
325 final String encoding,
326 final int bufferSize )
327 throws IOException
328 {
329 final InputStreamReader in = new InputStreamReader( input, encoding );
330 copy( in, output, bufferSize );
331 }
332
333
334
335
336
337 /***
338 * Get the contents of an <code>InputStream</code> as a String.
339 * The platform's default encoding is used for the byte-to-char conversion.
340 */
341 public static String toString( final InputStream input )
342 throws IOException
343 {
344 return toString( input, DEFAULT_BUFFER_SIZE );
345 }
346
347 /***
348 * Get the contents of an <code>InputStream</code> as a String.
349 * The platform's default encoding is used for the byte-to-char conversion.
350 * @param bufferSize Size of internal buffer to use.
351 */
352 public static String toString( final InputStream input, final int bufferSize )
353 throws IOException
354 {
355 final StringWriter sw = new StringWriter();
356 copy( input, sw, bufferSize );
357 return sw.toString();
358 }
359
360 /***
361 * Get the contents of an <code>InputStream</code> as a String.
362 * @param encoding The name of a supported character encoding. See the
363 * <a href="http://www.iana.org/assignments/character-sets">IANA
364 * Charset Registry</a> for a list of valid encoding types.
365 */
366 public static String toString( final InputStream input, final String encoding )
367 throws IOException
368 {
369 return toString( input, encoding, DEFAULT_BUFFER_SIZE );
370 }
371
372 /***
373 * Get the contents of an <code>InputStream</code> as a String.
374 * @param encoding The name of a supported character encoding. See the
375 * <a href="http://www.iana.org/assignments/character-sets">IANA
376 * Charset Registry</a> for a list of valid encoding types.
377 * @param bufferSize Size of internal buffer to use.
378 */
379 public static String toString( final InputStream input,
380 final String encoding,
381 final int bufferSize )
382 throws IOException
383 {
384 final StringWriter sw = new StringWriter();
385 copy( input, sw, encoding, bufferSize );
386 return sw.toString();
387 }
388
389
390
391
392 /***
393 * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
394 */
395 public static byte[] toByteArray( final InputStream input )
396 throws IOException
397 {
398 return toByteArray( input, DEFAULT_BUFFER_SIZE );
399 }
400
401 /***
402 * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
403 * @param bufferSize Size of internal buffer to use.
404 */
405 public static byte[] toByteArray( final InputStream input, final int bufferSize )
406 throws IOException
407 {
408 final ByteArrayOutputStream output = new ByteArrayOutputStream();
409 copy( input, output, bufferSize );
410 return output.toByteArray();
411 }
412
413
414
415
416
417
418
419
420
421 /***
422 * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
423 * flush the <code>OutputStream</code>.
424 */
425 public static void copy( final Reader input, final OutputStream output )
426 throws IOException
427 {
428 copy( input, output, DEFAULT_BUFFER_SIZE );
429 }
430
431 /***
432 * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
433 * flush the <code>OutputStream</code>.
434 * @param bufferSize Size of internal buffer to use.
435 */
436 public static void copy( final Reader input, final OutputStream output, final int bufferSize )
437 throws IOException
438 {
439 final OutputStreamWriter out = new OutputStreamWriter( output );
440 copy( input, out, bufferSize );
441
442
443 out.flush();
444 }
445
446
447
448 /***
449 * Get the contents of a <code>Reader</code> as a String.
450 */
451 public static String toString( final Reader input )
452 throws IOException
453 {
454 return toString( input, DEFAULT_BUFFER_SIZE );
455 }
456
457 /***
458 * Get the contents of a <code>Reader</code> as a String.
459 * @param bufferSize Size of internal buffer to use.
460 */
461 public static String toString( final Reader input, final int bufferSize )
462 throws IOException
463 {
464 final StringWriter sw = new StringWriter();
465 copy( input, sw, bufferSize );
466 return sw.toString();
467 }
468
469
470
471
472 /***
473 * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
474 */
475 public static byte[] toByteArray( final Reader input )
476 throws IOException
477 {
478 return toByteArray( input, DEFAULT_BUFFER_SIZE );
479 }
480
481 /***
482 * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
483 * @param bufferSize Size of internal buffer to use.
484 */
485 public static byte[] toByteArray( final Reader input, final int bufferSize )
486 throws IOException
487 {
488 ByteArrayOutputStream output = new ByteArrayOutputStream();
489 copy( input, output, bufferSize );
490 return output.toByteArray();
491 }
492
493
494
495
496
497
498
499
500
501
502
503 /***
504 * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
505 * flush the <code>OutputStream</code>.
506 */
507 public static void copy( final String input, final OutputStream output )
508 throws IOException
509 {
510 copy( input, output, DEFAULT_BUFFER_SIZE );
511 }
512
513 /***
514 * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
515 * flush the <code>OutputStream</code>.
516 * @param bufferSize Size of internal buffer to use.
517 */
518 public static void copy( final String input, final OutputStream output, final int bufferSize )
519 throws IOException
520 {
521 final StringReader in = new StringReader( input );
522 final OutputStreamWriter out = new OutputStreamWriter( output );
523 copy( in, out, bufferSize );
524
525
526 out.flush();
527 }
528
529
530
531
532
533
534 /***
535 * Copy chars from a <code>String</code> to a <code>Writer</code>.
536 */
537 public static void copy( final String input, final Writer output )
538 throws IOException
539 {
540 output.write( input );
541 }
542
543
544
545 /***
546 * Get the contents of a <code>String</code> as a <code>byte[]</code>.
547 */
548 public static byte[] toByteArray( final String input )
549 throws IOException
550 {
551 return toByteArray( input, DEFAULT_BUFFER_SIZE );
552 }
553
554 /***
555 * Get the contents of a <code>String</code> as a <code>byte[]</code>.
556 * @param bufferSize Size of internal buffer to use.
557 */
558 public static byte[] toByteArray( final String input, final int bufferSize )
559 throws IOException
560 {
561 ByteArrayOutputStream output = new ByteArrayOutputStream();
562 copy( input, output, bufferSize );
563 return output.toByteArray();
564 }
565
566
567
568
569
570
571
572
573
574
575
576
577 /***
578 * Copy and convert bytes from a <code>byte[]</code> to chars on a
579 * <code>Writer</code>.
580 * The platform's default encoding is used for the byte-to-char conversion.
581 */
582 public static void copy( final byte[] input, final Writer output )
583 throws IOException
584 {
585 copy( input, output, DEFAULT_BUFFER_SIZE );
586 }
587
588 /***
589 * Copy and convert bytes from a <code>byte[]</code> to chars on a
590 * <code>Writer</code>.
591 * The platform's default encoding is used for the byte-to-char conversion.
592 * @param bufferSize Size of internal buffer to use.
593 */
594 public static void copy( final byte[] input, final Writer output, final int bufferSize )
595 throws IOException
596 {
597 final ByteArrayInputStream in = new ByteArrayInputStream( input );
598 copy( in, output, bufferSize );
599 }
600
601 /***
602 * Copy and convert bytes from a <code>byte[]</code> to chars on a
603 * <code>Writer</code>, using the specified encoding.
604 * @param encoding The name of a supported character encoding. See the
605 * <a href="http://www.iana.org/assignments/character-sets">IANA
606 * Charset Registry</a> for a list of valid encoding types.
607 */
608 public static void copy( final byte[] input, final Writer output, final String encoding )
609 throws IOException
610 {
611 final ByteArrayInputStream in = new ByteArrayInputStream( input );
612 copy( in, output, encoding );
613 }
614
615 /***
616 * Copy and convert bytes from a <code>byte[]</code> to chars on a
617 * <code>Writer</code>, using the specified encoding.
618 * @param encoding The name of a supported character encoding. See the
619 * <a href="http://www.iana.org/assignments/character-sets">IANA
620 * Charset Registry</a> for a list of valid encoding types.
621 * @param bufferSize Size of internal buffer to use.
622 */
623 public static void copy( final byte[] input,
624 final Writer output,
625 final String encoding,
626 final int bufferSize )
627 throws IOException
628 {
629 final ByteArrayInputStream in = new ByteArrayInputStream( input );
630 copy( in, output, encoding, bufferSize );
631 }
632
633
634
635
636
637 /***
638 * Get the contents of a <code>byte[]</code> as a String.
639 * The platform's default encoding is used for the byte-to-char conversion.
640 */
641 public static String toString( final byte[] input )
642 throws IOException
643 {
644 return toString( input, DEFAULT_BUFFER_SIZE );
645 }
646
647 /***
648 * Get the contents of a <code>byte[]</code> as a String.
649 * The platform's default encoding is used for the byte-to-char conversion.
650 * @param bufferSize Size of internal buffer to use.
651 */
652 public static String toString( final byte[] input, final int bufferSize )
653 throws IOException
654 {
655 final StringWriter sw = new StringWriter();
656 copy( input, sw, bufferSize );
657 return sw.toString();
658 }
659
660 /***
661 * Get the contents of a <code>byte[]</code> as a String.
662 * @param encoding The name of a supported character encoding. See the
663 * <a href="http://www.iana.org/assignments/character-sets">IANA
664 * Charset Registry</a> for a list of valid encoding types.
665 */
666 public static String toString( final byte[] input, final String encoding )
667 throws IOException
668 {
669 return toString( input, encoding, DEFAULT_BUFFER_SIZE );
670 }
671
672 /***
673 * Get the contents of a <code>byte[]</code> as a String.
674 * @param encoding The name of a supported character encoding. See the
675 * <a href="http://www.iana.org/assignments/character-sets">IANA
676 * Charset Registry</a> for a list of valid encoding types.
677 * @param bufferSize Size of internal buffer to use.
678 */
679 public static String toString( final byte[] input,
680 final String encoding,
681 final int bufferSize )
682 throws IOException
683 {
684 final StringWriter sw = new StringWriter();
685 copy( input, sw, encoding, bufferSize );
686 return sw.toString();
687 }
688
689
690
691
692
693 /***
694 * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
695 */
696 public static void copy( final byte[] input, final OutputStream output )
697 throws IOException
698 {
699 copy( input, output, DEFAULT_BUFFER_SIZE );
700 }
701
702 /***
703 * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
704 * @param bufferSize Size of internal buffer to use.
705 */
706 public static void copy( final byte[] input,
707 final OutputStream output,
708 final int bufferSize )
709 throws IOException
710 {
711 output.write( input );
712 }
713
714 /***
715 * Compare the contents of two Streams to determine if they are equal or not.
716 *
717 * @param input1 the first stream
718 * @param input2 the second stream
719 * @return true if the content of the streams are equal or they both don't exist, false otherwise
720 */
721 public static boolean contentEquals( final InputStream input1,
722 final InputStream input2 )
723 throws IOException
724 {
725 final InputStream bufferedInput1 = new BufferedInputStream( input1 );
726 final InputStream bufferedInput2 = new BufferedInputStream( input2 );
727
728 int ch = bufferedInput1.read();
729 while( -1 != ch )
730 {
731 final int ch2 = bufferedInput2.read();
732 if( ch != ch2 )
733 {
734 return false;
735 }
736 ch = bufferedInput1.read();
737 }
738
739 final int ch2 = bufferedInput2.read();
740 if( -1 != ch2 )
741 {
742 return false;
743 }
744 else
745 {
746 return true;
747 }
748 }
749 }