001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.common.internal; 014 015import java.io.*; 016import java.nio.charset.*; 017import java.util.*; 018import java.util.concurrent.atomic.*; 019import java.util.function.*; 020 021/** 022 * Various I/O related utility methods. 023 */ 024public final class IOUtils { 025 026 /** UTF-8 charset */ 027 public static final Charset UTF8 = Charset.forName("UTF-8"); 028 029 /** Reusable empty input stream. */ 030 public static final InputStream EMPTY_INPUT_STREAM = new InputStream() { 031 @Override 032 public int read() { 033 return -1; // end of stream 034 } 035 }; 036 037 private static final int BUFF_SIZE = 1024; 038 private static final ThreadLocal<byte[]> BYTE_BUFFER_CACHE = (Boolean.getBoolean("juneau.disableIoBufferReuse") ? null : new ThreadLocal<>()); 039 private static final ThreadLocal<char[]> CHAR_BUFFER_CACHE = (Boolean.getBoolean("juneau.disableIoBufferReuse") ? null : new ThreadLocal<>()); 040 041 static final AtomicInteger BYTE_BUFFER_CACHE_HITS = new AtomicInteger(); 042 static final AtomicInteger BYTE_BUFFER_CACHE_MISSES = new AtomicInteger(); 043 static final AtomicInteger CHAR_BUFFER_CACHE_HITS = new AtomicInteger(); 044 static final AtomicInteger CHAR_BUFFER_CACHE_MISSES = new AtomicInteger(); 045 046 static { 047 SystemUtils.shutdownMessage(()->"Byte buffer cache: hits="+BYTE_BUFFER_CACHE_HITS.get()+", misses=" + BYTE_BUFFER_CACHE_MISSES); 048 SystemUtils.shutdownMessage(()->"Char buffer cache: hits="+CHAR_BUFFER_CACHE_HITS.get()+", misses=" + CHAR_BUFFER_CACHE_MISSES); 049 } 050 051 /** Reusable empty reader. */ 052 public static final Reader EMPTY_READER = new Reader() { 053 @Override 054 public int read() { 055 return -1; // end of stream 056 } 057 @Override 058 public int read(char[] cbuf, int off, int len) throws IOException { 059 return -1; // end of stream 060 } 061 @Override 062 public void close() throws IOException {} 063 }; 064 065 //----------------------------------------------------------------------------------------------------------------- 066 // Piping utilities. 067 //----------------------------------------------------------------------------------------------------------------- 068 069 /** 070 * Pipes the contents of the specified <c>Reader</c> to the specified file. 071 * 072 * @param in 073 * The reader to pipe from. 074 * <br>Can be <jk>null</jk>. 075 * <br>Reader is automatically closed. 076 * @param out 077 * The file to write the output to. 078 * <br>Can be <jk>null</jk>. 079 * @return 080 * The number of characters piped. 081 * @throws IOException Thrown by underlying stream. 082 */ 083 public static long pipe(Reader in, File out) throws IOException { 084 if (out == null || in == null) 085 return 0; 086 try (Writer w = FileWriterBuilder.create(out).buffered().build()) { 087 return pipe(in, w); 088 } 089 } 090 091 /** 092 * Pipes the contents of the specified <c>Reader</c> to the specified <c>Writer</c>. 093 * 094 * @param in 095 * The reader to pipe from. 096 * <br>Can be <jk>null</jk>. 097 * <br>Reader is automatically closed. 098 * @param out 099 * The file to write the output to. 100 * <br>Can be <jk>null</jk>. 101 * <br>Writer is flushed but not automatically closed. 102 * @return 103 * The number of characters piped. 104 * @throws IOException Thrown by underlying stream. 105 */ 106 public static long pipe(Reader in, Writer out) throws IOException { 107 if (out == null || in == null) 108 return 0; 109 long total = 0; 110 try (Reader in2 = in) { 111 char[] buffer = charBuffer(-1); 112 int readLen; 113 while ((readLen = in.read(buffer)) != -1) { 114 out.write(buffer, 0, readLen); 115 total += readLen; 116 } 117 } 118 out.flush(); 119 return total; 120 } 121 122 /** 123 * Pipes the contents of the specified <c>Reader</c> to the specified <c>Writer</c>. 124 * 125 * @param in 126 * The reader to pipe from. 127 * <br>Can be <jk>null</jk>. 128 * <br>Reader is automatically closed. 129 * @param out 130 * The file to write the output to. 131 * <br>Can be <jk>null</jk>. 132 * <br>Writer is flushed but not automatically closed. 133 * @param onException Consumer of any {@link IOException I/O exceptions}. 134 * @return 135 * The number of characters piped. 136 */ 137 public static long pipe(Reader in, Writer out, Consumer<IOException> onException) { 138 try { 139 return pipe(in, out); 140 } catch (IOException e) { 141 onException.accept(e); 142 return -1; 143 } 144 } 145 146 /** 147 * Pipes the contents of the specified <c>Reader</c> to the specified <c>Writer</c> a line at a time. 148 * 149 * <p> 150 * Writer is flushed after every line. Typically useful when writing to consoles. 151 * 152 * @param in 153 * The reader to pipe from. 154 * <br>Can be <jk>null</jk>. 155 * <br>Reader is automatically closed. 156 * @param out 157 * The file to write the output to. 158 * <br>Can be <jk>null</jk>. 159 * <br>Writer is flushed but not automatically closed. 160 * @return 161 * The number of characters piped. 162 * @throws IOException Thrown by underlying stream. 163 */ 164 public static long pipeLines(Reader in, Writer out) throws IOException { 165 if (in == null || out == null) 166 return 0; 167 long total = 0; 168 try (Reader in2 = in) { 169 try (Scanner s = new Scanner(in2)) { 170 while (s.hasNextLine()) { 171 String l = s.nextLine(); 172 if (l != null) { 173 out.write(l); 174 out.write("\n"); 175 out.flush(); 176 total += l.length() + 1; 177 } 178 } 179 } 180 } 181 return total; 182 } 183 184 /** 185 * Pipes the contents of the specified input stream to the writer. 186 * 187 * @param in 188 * The stream to pipe from. 189 * <br>Can be <jk>null</jk>. 190 * <br>Streams is automatically closed. 191 * @param out 192 * The writer to pipe to. 193 * <br>Can be <jk>null</jk>. 194 * <br>Stream is not automatically closed. 195 * @return 196 * The number of bytes written. 197 * @throws IOException Thrown by underlying stream. 198 */ 199 public static long pipe(InputStream in, Writer out) throws IOException { 200 if (in == null || out == null) 201 return 0; 202 return pipe(new InputStreamReader(in, UTF8), out); 203 } 204 205 /** 206 * Pipes the contents of the specified input stream to the writer. 207 * 208 * @param in 209 * The stream to pipe from. 210 * <br>Can be <jk>null</jk>. 211 * <br>Streams is automatically closed. 212 * @param out 213 * The writer to pipe to. 214 * <br>Can be <jk>null</jk>. 215 * <br>Stream is not automatically closed. 216 * @param onException Consumer of any {@link IOException I/O exceptions}. 217 * @return 218 * The number of bytes written. 219 */ 220 public static long pipe(InputStream in, Writer out, Consumer<IOException> onException) { 221 try { 222 if (in == null || out == null) 223 return 0; 224 return pipe(new InputStreamReader(in, UTF8), out); 225 } catch (IOException e) { 226 onException.accept(e); 227 return -2; 228 } 229 } 230 231 /** 232 * Pipes the specified input stream to the specified output stream. 233 * 234 * <p> 235 * Either stream is not automatically closed. 236 * 237 * @param in 238 * The input stream. 239 * <br>Can be <jk>null</jk>. 240 * <br>Stream is automatically closed. 241 * @param out 242 * The output stream. 243 * <br>Can be <jk>null</jk>. 244 * <br>Stream is not automatically closed. 245 * @return The number of bytes written. 246 * @throws IOException If thrown from either stream. 247 */ 248 public static long pipe(InputStream in, OutputStream out) throws IOException { 249 try (InputStream in2 = in) { 250 return pipe(in, out, -1); 251 } 252 } 253 254 /** 255 * Pipes the specified input stream to the specified output stream. 256 * 257 * <p> 258 * Either stream is not automatically closed. 259 * 260 * @param in 261 * The input stream. 262 * <br>Can be <jk>null</jk>. 263 * <br>Stream is automatically closed. 264 * @param out 265 * The output stream. 266 * <br>Can be <jk>null</jk>. 267 * <br>Stream is not automatically closed. 268 * @param onException Consumer of any {@link IOException I/O exceptions}. 269 * @return The number of bytes written. 270 */ 271 public static long pipe(InputStream in, OutputStream out, Consumer<IOException> onException) { 272 try { 273 try (InputStream in2 = in) { 274 return pipe(in, out, -1); 275 } 276 } catch (IOException e) { 277 onException.accept(e); 278 return -1; 279 } 280 } 281 282 /** 283 * Pipes the specified input stream to the specified output stream. 284 * 285 * <p> 286 * Either stream is not automatically closed. 287 * 288 * @param in 289 * The input stream. 290 * <br>Can be <jk>null</jk>. 291 * <br>Stream is not automatically closed. 292 * @param out 293 * The output stream. 294 * <br>Can be <jk>null</jk>. 295 * <br>Stream is not automatically closed. 296 * @param maxBytes 297 * The maximum number of bytes or <c>-1</c> to read the entire input stream. 298 * @return The number of bytes written. 299 * @throws IOException If thrown from either stream. 300 */ 301 public static long pipe(InputStream in, OutputStream out, long maxBytes) throws IOException { 302 if (in == null || out == null) 303 return 0; 304 byte[] buffer = byteBuffer((int)maxBytes); 305 int readLen; 306 long total = 0; 307 if (maxBytes < 0) { 308 while ((readLen = in.read(buffer)) != -1) { 309 out.write(buffer, 0, readLen); 310 total += readLen; 311 } 312 } else { 313 long remaining = maxBytes; 314 while (remaining > 0) { 315 readLen = in.read(buffer, 0, buffSize(remaining)); 316 if (readLen == -1) 317 break; 318 out.write(buffer, 0, readLen); 319 total += readLen; 320 remaining -= readLen; 321 } 322 } 323 out.flush(); 324 return total; 325 } 326 327 /** 328 * Pipes the specified reader to the specified output stream. 329 * 330 * @param in 331 * The input reader. 332 * <br>Can be <jk>null</jk>. 333 * <br>Stream is automatically closed. 334 * @param out 335 * The output stream. 336 * <br>Can be <jk>null</jk>. 337 * <br>Stream is not automatically closed. 338 * @return The number of bytes written. 339 * @throws IOException If thrown from output stream. 340 */ 341 public static long pipe(Reader in, OutputStream out) throws IOException { 342 if (in == null || out == null) 343 return 0; 344 long total = 0; 345 try (Reader in2 = in) { 346 OutputStreamWriter osw = new OutputStreamWriter(out, UTF8); 347 int i; 348 char[] b = charBuffer(-1); 349 while ((i = in.read(b)) > 0) { 350 total += i; 351 osw.write(b, 0, i); 352 } 353 osw.flush(); 354 } 355 return total; 356 } 357 358 /** 359 * Pipes the specified reader to the specified output stream. 360 * 361 * @param in 362 * The input reader. 363 * <br>Can be <jk>null</jk>. 364 * <br>Stream is automatically closed. 365 * @param out 366 * The output stream. 367 * <br>Can be <jk>null</jk>. 368 * <br>Stream is not automatically closed. 369 * @param onException Consumer of any {@link IOException I/O exceptions}. 370 * @return The number of bytes written. 371 */ 372 public static long pipe(Reader in, OutputStream out, Consumer<IOException> onException) { 373 try { 374 return pipe(in, out); 375 } catch (IOException e) { 376 onException.accept(e); 377 return -1; 378 } 379 } 380 381 /** 382 * Pipes the specified byte array to the specified output stream. 383 * 384 * @param in 385 * The input byte array. 386 * <br>Can be <jk>null</jk>. 387 * @param out 388 * The output stream. 389 * <br>Can be <jk>null</jk>. 390 * <br>Stream is not automatically closed. 391 * @param maxBytes 392 * The maximum number of bytes or <c>-1</c> to read the entire byte array. 393 * @return The number of bytes written. 394 * @throws IOException If thrown from output stream. 395 */ 396 public static final long pipe(byte[] in, OutputStream out, int maxBytes) throws IOException { 397 if (in == null || out == null) 398 return 0; 399 int length = (maxBytes < 0 || maxBytes > in.length ) ? in.length : maxBytes; 400 out.write(in, 0, length); 401 return length; 402 } 403 404 //----------------------------------------------------------------------------------------------------------------- 405 // Reading utilities. 406 //----------------------------------------------------------------------------------------------------------------- 407 408 /** 409 * Pipes the specified object to the specified output stream. 410 * 411 * @param in 412 * The input byte array. 413 * <br>Can be <jk>null</jk> or any of the following types: 414 * <ul> 415 * <li>{@link Reader} 416 * <li>{@link InputStream} 417 * <li>{@link File} 418 * <li>byte array. 419 * </ul> 420 * @return The input converted to a string. 421 * @throws IOException If thrown from output stream. 422 */ 423 public static String read(Object in) throws IOException { 424 if (in == null) 425 return null; 426 if (in instanceof Reader) 427 return read((Reader)in); 428 if (in instanceof InputStream) 429 return read((InputStream)in); 430 if (in instanceof File) 431 return read((File)in); 432 if (in instanceof byte[]) 433 return read((byte[])in); 434 throw new RuntimeException("Invalid type passed to read: " + in.getClass().getName()); 435 } 436 437 /** 438 * Reads the specified byte array containing UTF-8 into a string. 439 * 440 * @param in 441 * The input. 442 * <br>Can be <jk>null</jk>. 443 * @return The new string, or <jk>null</jk> if the input was null. 444 */ 445 public static String read(byte[] in) { 446 return read(in, UTF8); 447 } 448 449 /** 450 * Reads the specified byte array into a string. 451 * 452 * @param in 453 * The input. 454 * <br>Can be <jk>null</jk>. 455 * @param charset The character set to use for decoding. 456 * @return The new string, or <jk>null</jk> if the input was null. 457 */ 458 public static String read(byte[] in, Charset charset) { 459 if (in == null) 460 return null; 461 return new String(in, charset); 462 } 463 464 /** 465 * Reads the contents of a file into a string. 466 * 467 * <p> 468 * Assumes default character encoding. 469 * 470 * @param in 471 * The file to read. 472 * <br>Can be <jk>null</jk>. 473 * @return 474 * The contents of the reader as a string, or <jk>null</jk> if file does not exist. 475 * @throws IOException If a problem occurred trying to read from the reader. 476 */ 477 public static String read(File in) throws IOException { 478 if (in == null || ! in.exists()) 479 return null; 480 try (Reader r = FileReaderBuilder.create(in).build()) { 481 return read(r, in.length()); 482 } 483 } 484 485 /** 486 * Reads the contents of a reader into a string. 487 * 488 * @param in 489 * The input reader. 490 * <br>Can be <jk>null</jk>. 491 * <br>Stream is automatically closed. 492 * @return 493 * The contents of the reader as a string, or <jk>null</jk> if the reader was <jk>null</jk>. 494 * @throws IOException If a problem occurred trying to read from the reader. 495 */ 496 public static String read(Reader in) throws IOException { 497 try (Reader in2 = in) { 498 return read(in, -1); 499 } 500 } 501 502 /** 503 * Reads the contents of a reader into a string. 504 * 505 * @param in 506 * The input reader. 507 * <br>Can be <jk>null</jk>. 508 * <br>Stream is automatically closed. 509 * @param onException Consumer of any {@link IOException I/O exceptions}. 510 * @return 511 * The contents of the reader as a string, or <jk>null</jk> if the reader was <jk>null</jk>. 512 */ 513 public static String read(Reader in, Consumer<IOException> onException) { 514 try (Reader in2 = in) { 515 return read(in, -1); 516 } catch (IOException e) { 517 onException.accept(e); 518 return null; 519 } 520 } 521 522 /** 523 * Reads the specified input into a {@link String} until the end of the input is reached. 524 * 525 * @param in 526 * The input reader. 527 * <br>Can be <jk>null</jk>. 528 * <br>String is automatically closed. 529 * @param expectedLength 530 * Specify a positive number if the length of the input is known, or <c>-1</c> if unknown. 531 * @return 532 * The contents of the reader as a string, or <jk>null</jk> if the reader was <jk>null</jk>. 533 * @throws IOException If a problem occurred trying to read from the reader. 534 */ 535 public static String read(Reader in, long expectedLength) throws IOException { 536 if (in == null) 537 return null; 538 try (Reader in2 = in) { 539 StringBuilder sb = new StringBuilder(buffSize(expectedLength)); // Assume they're ASCII characters. 540 char[] buf = charBuffer((int)expectedLength); 541 int i = 0; 542 while ((i = in2.read(buf)) != -1) 543 sb.append(buf, 0, i); 544 return sb.toString(); 545 } 546 } 547 548 /** 549 * Reads the contents of an input stream into a string. 550 * 551 * <p> 552 * Assumes UTF-8 encoding. 553 * 554 * @param in 555 * The input stream. 556 * <br>Can be <jk>null</jk>. 557 * <br>Stream is automatically closed. 558 * @return 559 * The contents of the reader as a string, or <jk>null</jk> if the input stream was <jk>null</jk>. 560 * @throws IOException If a problem occurred trying to read from the input stream. 561 */ 562 public static String read(InputStream in) throws IOException { 563 return read(in, UTF8); 564 } 565 566 /** 567 * Reads the contents of an input stream into a string. 568 * 569 * <p> 570 * Assumes UTF-8 encoding. 571 * 572 * @param in 573 * The input stream. 574 * <br>Can be <jk>null</jk>. 575 * <br>Stream is automatically closed. 576 * @param onException Consumer of any {@link IOException I/O exceptions}. 577 * @return 578 * The contents of the reader as a string, or <jk>null</jk> if the input stream was <jk>null</jk>. 579 */ 580 public static String read(InputStream in, Consumer<IOException> onException) { 581 return read(in, UTF8, onException); 582 } 583 584 /** 585 * Reads the contents of an input stream into a string using the specified charset. 586 * 587 * @param in 588 * The input stream. 589 * <br>Can be <jk>null</jk>. 590 * <br>Stream is automatically closed. 591 * @param cs 592 * The charset of the contents of the input stream. 593 * @return 594 * The contents of the reader as a string or <jk>null</jk> if input stream was <jk>null</jk>. 595 * @throws IOException If a problem occurred trying to read from the input stream. 596 */ 597 public static String read(InputStream in, Charset cs) throws IOException { 598 if (in == null) 599 return null; 600 try (InputStreamReader isr = new InputStreamReader(in, cs)) { 601 return read(isr); 602 } 603 } 604 605 /** 606 * Reads the contents of an input stream into a string using the specified charset. 607 * 608 * @param in 609 * The input stream. 610 * <br>Can be <jk>null</jk>. 611 * <br>Stream is automatically closed. 612 * @param cs 613 * The charset of the contents of the input stream. 614 * @param onException Consumer of any {@link IOException I/O exceptions}. 615 * @return 616 * The contents of the reader as a string or <jk>null</jk> if input stream was <jk>null</jk>. 617 */ 618 public static String read(InputStream in, Charset cs, Consumer<IOException> onException) { 619 if (in == null) 620 return null; 621 try (InputStreamReader isr = new InputStreamReader(in, cs)) { 622 return read(isr); 623 } catch (IOException e) { 624 onException.accept(e); 625 return null; 626 } 627 } 628 629 /** 630 * Reads the specified input stream into the specified byte array. 631 * 632 * @param in 633 * The input stream to read. 634 * <br>Can be <jk>null</jk>. 635 * <br>Stream is automatically closed. 636 * @return A byte array containing the contents. Never <jk>null</jk>. 637 * @throws IOException Thrown by underlying stream. 638 */ 639 public static byte[] readBytes(InputStream in) throws IOException { 640 try (InputStream in2 = in) { 641 return readBytes(in2, -1); 642 } 643 } 644 645 /** 646 * Reads the specified input stream into the specified byte array. 647 * 648 * @param in 649 * The input stream to read. 650 * <br>Can be <jk>null</jk>. 651 * <br>Stream is not automatically closed. 652 * @param maxBytes 653 * The maximum number of bytes or <c>-1</c> to read the entire stream. 654 * @return A byte array containing the contents. Never <jk>null</jk>. 655 * @throws IOException Thrown by underlying stream. 656 */ 657 public static byte[] readBytes(InputStream in, int maxBytes) throws IOException { 658 if (in == null) 659 return new byte[0]; 660 ByteArrayOutputStream buff = new ByteArrayOutputStream(buffSize(maxBytes)); 661 int nRead; 662 byte[] b = byteBuffer(maxBytes); 663 while ((nRead = in.read(b, 0, b.length)) != -1) 664 buff.write(b, 0, nRead); 665 buff.flush(); 666 return buff.toByteArray(); 667 } 668 669 /** 670 * Read the specified file into a byte array. 671 * 672 * @param in 673 * The file to read into a byte array. 674 * @return The contents of the file as a byte array. 675 * @throws IOException Thrown by underlying stream. 676 */ 677 public static byte[] readBytes(File in) throws IOException { 678 return readBytes(in, -1); 679 } 680 681 /** 682 * Read the specified file into a byte array. 683 * 684 * @param in 685 * The file to read into a byte array. 686 * @param maxBytes 687 * The maximum number of bytes to read, or <jk>-1</jk> to read all bytes. 688 * @return The contents of the file as a byte array. 689 * @throws IOException Thrown by underlying stream. 690 */ 691 public static byte[] readBytes(File in, int maxBytes) throws IOException { 692 if (in == null || ! (in.exists() && in.canRead())) 693 return new byte[0]; 694 try (FileInputStream is = new FileInputStream(in)) { 695 return readBytes(is, maxBytes); 696 } 697 } 698 699 /** 700 * Reads the specified input stream into the specified byte array. 701 * 702 * @param in 703 * The input stream to read. 704 * <br>Can be <jk>null</jk>. 705 * <br>Stream is automatically closed. 706 * @return A byte array containing the contents. Never <jk>null</jk>. 707 * @throws IOException Thrown by underlying stream. 708 */ 709 public static byte[] readBytes(Reader in) throws IOException { 710 if (in == null) 711 return new byte[0]; 712 try (Reader in2 = in) { 713 return read(in2, -1).getBytes(); 714 } 715 } 716 717 //----------------------------------------------------------------------------------------------------------------- 718 // Other utilities. 719 //----------------------------------------------------------------------------------------------------------------- 720 721 /** 722 * Wraps the specified reader in a buffered reader. 723 * 724 * @param r The reader being wrapped. 725 * @return 726 * The reader wrapped in a {@link BufferedReader}, or the original {@link Reader} if it's already a buffered 727 * reader. 728 */ 729 public static Reader toBufferedReader(Reader r) { 730 if (r == null || r instanceof BufferedReader || r instanceof StringReader) 731 return r; 732 return new BufferedReader(r); 733 } 734 735 /** 736 * Counts the number of bytes in the input stream and then closes the stream. 737 * 738 * @param is The input stream to read from. 739 * @return The number of bytes read. 740 * @throws IOException Thrown by underlying stream. 741 */ 742 public static long count(InputStream is) throws IOException { 743 if (is == null) 744 return 0; 745 long c = 0; 746 long i; 747 try { 748 while ((i = is.skip(1024)) != 0) 749 c += i; 750 } finally { 751 is.close(); 752 } 753 return c; 754 } 755 756 /** 757 * Counts the number of characters in the reader and then closes the reader. 758 * 759 * @param r The reader to read from. 760 * @return The number of characters read. 761 * @throws IOException Thrown by underlying stream. 762 */ 763 public static long count(Reader r) throws IOException { 764 if (r == null) 765 return 0; 766 long c = 0; 767 long i; 768 try { 769 while ((i = r.skip(1024)) != 0) 770 c += i; 771 } finally { 772 r.close(); 773 } 774 return c; 775 } 776 777 /** 778 * Close input stream and ignore any exceptions. 779 * 780 * <p> 781 * No-op if input stream is <jk>null</jk>. 782 * 783 * @param is The input stream to close. 784 */ 785 public static void closeQuietly(InputStream is) { 786 try { 787 if (is != null) 788 is.close(); 789 } catch (IOException e) {} 790 } 791 792 /** 793 * Close output stream and ignore any exceptions. 794 * 795 * <p> 796 * No-op if output stream is <jk>null</jk>. 797 * 798 * @param os The output stream to close. 799 */ 800 public static void closeQuietly(OutputStream os) { 801 try { 802 if (os != null) 803 os.close(); 804 } catch (IOException e) {} 805 } 806 807 /** 808 * Close reader and ignore any exceptions. 809 * 810 * <p> 811 * No-op if reader is <jk>null</jk>. 812 * 813 * @param r The reader to close. 814 */ 815 public static void closeQuietly(Reader r) { 816 try { 817 if (r != null) 818 r.close(); 819 } catch (IOException e) {} 820 } 821 822 /** 823 * Close writer and ignore any exceptions. 824 * 825 * <p> 826 * No-op if writer is <jk>null</jk>. 827 * 828 * @param w The writer to close. 829 */ 830 public static void closeQuietly(Writer w) { 831 try { 832 if (w != null) 833 w.close(); 834 } catch (IOException e) {} 835 } 836 837 /** 838 * Quietly close all specified input streams, output streams, readers, and writers. 839 * 840 * @param o The list of all objects to quietly close. 841 */ 842 public static void closeQuietly(Object...o) { 843 for (Object o2 : o) { 844 if (o2 instanceof InputStream) 845 closeQuietly((InputStream)o2); 846 if (o2 instanceof OutputStream) 847 closeQuietly((OutputStream)o2); 848 if (o2 instanceof Reader) 849 closeQuietly((Reader)o2); 850 if (o2 instanceof Writer) 851 closeQuietly((Writer)o2); 852 } 853 } 854 855 /** 856 * Flushes multiple output streams and writers in a single call. 857 * 858 * @param o 859 * The objects to flush. 860 * <jk>null</jk> entries are ignored. 861 * @throws IOException Thrown by underlying stream. 862 */ 863 public static void flush(Object...o) throws IOException { 864 IOException ex = null; 865 for (Object o2 : o) { 866 try { 867 if (o2 instanceof OutputStream) 868 ((OutputStream)o2).flush(); 869 if (o2 instanceof Writer) 870 ((Writer)o2).flush(); 871 } catch (IOException e) { 872 ex = e; 873 } 874 } 875 if (ex != null) 876 throw ex; 877 } 878 879 /** 880 * Close all specified input streams, output streams, readers, and writers. 881 * 882 * @param o 883 * The list of all objects to close. 884 * <jk>null</jk> entries are ignored. 885 * @throws IOException Thrown by underlying stream. 886 */ 887 public static void close(Object...o) throws IOException { 888 IOException ex = null; 889 for (Object o2 : o) { 890 try { 891 if (o2 instanceof InputStream) 892 ((InputStream)o2).close(); 893 if (o2 instanceof OutputStream) 894 ((OutputStream)o2).close(); 895 if (o2 instanceof Reader) 896 ((Reader)o2).close(); 897 if (o2 instanceof Writer) 898 ((Writer)o2).close(); 899 } catch (IOException e) { 900 ex = e; 901 } 902 } 903 if (ex != null) 904 throw ex; 905 } 906 907 /** 908 * Loads a text file from either the file system or classpath. 909 * 910 * @param name The file name. 911 * @param paths The paths to search. 912 * @return The file contents, or <jk>null</jk> if not found. 913 * @throws IOException Thrown by underlying stream. 914 */ 915 public static String loadSystemResourceAsString(String name, String...paths) throws IOException { 916 for (String path : paths) { 917 File p = new File(path); 918 if (p.exists()) { 919 File f = new File(p, name); 920 if (f.exists() && f.canRead()) 921 return read(f); 922 } 923 } 924 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 925 if (cl == null) 926 cl = ClassLoader.getSystemClassLoader(); 927 for (String path : paths) { 928 String n = ".".equals(path) ? name : path + '/' + name; 929 try (InputStream is = cl.getResourceAsStream(n)) { 930 if (is != null) 931 return read(is); 932 } 933 try (InputStream is = ClassLoader.getSystemResourceAsStream(n)) { 934 if (is != null) 935 return read(is); 936 } 937 } 938 return null; 939 } 940 941 private static final byte[] byteBuffer(int maxBytes) { 942 if (BYTE_BUFFER_CACHE != null) { 943 byte[] x = BYTE_BUFFER_CACHE.get(); 944 if (x == null) { 945 x = new byte[BUFF_SIZE]; 946 BYTE_BUFFER_CACHE.set(x); 947 BYTE_BUFFER_CACHE_MISSES.incrementAndGet(); 948 } else { 949 BYTE_BUFFER_CACHE_HITS.incrementAndGet(); 950 } 951 return x; 952 } 953 return new byte[buffSize(maxBytes)]; 954 } 955 956 private static final char[] charBuffer(int maxChars) { 957 if (CHAR_BUFFER_CACHE != null) { 958 char[] x = CHAR_BUFFER_CACHE.get(); 959 if (x == null) { 960 x = new char[BUFF_SIZE]; 961 CHAR_BUFFER_CACHE.set(x); 962 CHAR_BUFFER_CACHE_MISSES.incrementAndGet(); 963 } else { 964 CHAR_BUFFER_CACHE_HITS.incrementAndGet(); 965 } 966 return x; 967 } 968 return new char[buffSize(maxChars)]; 969 } 970 971 private static final int buffSize(long max) { 972 return (max > 0 && max < BUFF_SIZE) ? (int)max : BUFF_SIZE; 973 } 974}