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