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.internal; 014 015import static org.apache.juneau.internal.ThrowableUtils.*; 016 017import java.io.*; 018import java.nio.charset.*; 019 020import org.apache.juneau.*; 021import org.apache.juneau.utils.*; 022 023/** 024 * Various I/O related utility methods. 025 */ 026public final class IOUtils { 027 028 /** UTF-8 charset */ 029 public static final Charset UTF8 = Charset.forName("UTF-8"); 030 031 /** 032 * Reads the contents of a file into a string. 033 * 034 * @param path The path of the file to read using default character encoding. 035 * @return The contents of the reader as a string, or <jk>null</jk> if file does not exist. 036 * @throws IOException If a problem occurred trying to read from the reader. 037 */ 038 public static String readFile(String path) throws IOException { 039 return read(new File(path)); 040 } 041 042 /** 043 * Reads the contents of a file into a string. 044 * 045 * @param in The file to read using default character encoding. 046 * @return The contents of the reader as a string, or <jk>null</jk> if file does not exist. 047 * @throws IOException If a problem occurred trying to read from the reader. 048 */ 049 public static String read(File in) throws IOException { 050 if (in == null || ! in.exists()) 051 return null; 052 try (Reader r = FileReaderBuilder.create(in).build()) { 053 return read(r, 0, 1024); 054 } 055 } 056 057 /** 058 * Reads the specified object to a <code>String</code>. 059 * 060 * <p> 061 * Can be any of the following object types: 062 * <ul> 063 * <li>{@link CharSequence} 064 * <li>{@link File} 065 * <li>{@link Reader} 066 * <li>{@link InputStream} 067 * <li><code><jk>byte</jk>[]</code> 068 * </ul> 069 * 070 * @param o The object to read. 071 * @return The object serialized to a string, or <jk>null</jk> if it wasn't a supported type. 072 * @throws IOException 073 */ 074 public static String read(Object o) throws IOException { 075 if (o instanceof CharSequence) 076 return o.toString(); 077 if (o instanceof File) 078 return read((File)o); 079 if (o instanceof Reader) 080 return read((Reader)o); 081 if (o instanceof InputStream) 082 return read((InputStream)o); 083 if (o instanceof byte[]) 084 return read(new ByteArrayInputStream((byte[])o)); 085 return null; 086 } 087 088 /** 089 * Writes the contents of the specified <code>Reader</code> to the specified file. 090 * 091 * @param out The file to write the output to. 092 * @param in The reader to pipe from. 093 * @return The number of characters written to the file. 094 * @throws IOException 095 */ 096 public static int write(File out, Reader in) throws IOException { 097 assertFieldNotNull(out, "out"); 098 assertFieldNotNull(in, "in"); 099 try (Writer w = FileWriterBuilder.create(out).build()) { 100 return IOPipe.create(in, w).run(); 101 } 102 } 103 104 /** 105 * Writes the contents of the specified <code>InputStream</code> to the specified file. 106 * 107 * @param out The file to write the output to. 108 * @param in The input stream to pipe from. 109 * @return The number of characters written to the file. 110 * @throws IOException 111 */ 112 public static int write(File out, InputStream in) throws IOException { 113 assertFieldNotNull(out, "out"); 114 assertFieldNotNull(in, "in"); 115 try (OutputStream os = new FileOutputStream(out)) { 116 return IOPipe.create(in, os).run(); 117 } 118 } 119 120 /** 121 * Reads the contents of a reader into a string. 122 * 123 * @param in The input reader. 124 * @return The contents of the reader as a string. 125 * @throws IOException If a problem occurred trying to read from the reader. 126 */ 127 public static String read(Reader in) throws IOException { 128 return read(in, 0, 1024); 129 } 130 131 /** 132 * Reads the contents of an input stream into a string using the specified charset. 133 * 134 * @param in The input stream. 135 * @param cs The charset of the contents of the input stream. 136 * @return The contents of the reader as a string. <jk>null</jk> if input stream was null. 137 * @throws IOException If a problem occurred trying to read from the input stream. 138 */ 139 public static String read(InputStream in, Charset cs) throws IOException { 140 if (in == null) 141 return null; 142 return read(new InputStreamReader(in, cs)); 143 } 144 145 /** 146 * Reads the contents of an input stream into a string using the system default charset. 147 * 148 * @param in The input stream. 149 * @return The contents of the reader as a string, or <jk>null</jk> if the input stream is null. 150 * @throws IOException If a problem occurred trying to read from the input stream. 151 */ 152 public static String read(InputStream in) throws IOException { 153 if (in == null) 154 return null; 155 return read(new InputStreamReader(in, Charset.defaultCharset())); 156 } 157 158 /** 159 * Read the specified input stream into a byte array and closes the stream. 160 * 161 * @param in The input stream. 162 * @param bufferSize The expected size of the buffer. 163 * @return The contents of the stream as a byte array. 164 * @throws IOException Thrown by underlying stream. 165 */ 166 public static byte[] readBytes(InputStream in, int bufferSize) throws IOException { 167 if (in == null) 168 return null; 169 ByteArrayOutputStream buff = new ByteArrayOutputStream(bufferSize); 170 int nRead; 171 byte[] b = new byte[Math.min(bufferSize, 8192)]; 172 173 try { 174 while ((nRead = in.read(b, 0, b.length)) != -1) 175 buff.write(b, 0, nRead); 176 buff.flush(); 177 178 return buff.toByteArray(); 179 } finally { 180 in.close(); 181 } 182 } 183 184 /** 185 * Reads a raw stream of bytes from the specified file. 186 * 187 * @param f The file to read. 188 * @return A byte array containing the contents of the file. 189 * @throws IOException 190 */ 191 public static byte[] readBytes(File f) throws IOException { 192 if (f == null || ! (f.exists() && f.canRead())) 193 return null; 194 195 try (FileInputStream fis = new FileInputStream(f)) { 196 return readBytes(fis, (int)f.length()); 197 } 198 } 199 200 /** 201 * Reads the specified input into a {@link String} until the end of the input is reached. 202 * 203 * <p> 204 * The {@code Reader} is automatically closed. 205 * 206 * <p> 207 * If the {@code Reader} is not an instance of a {@code BufferedReader}, then it gets wrapped in a 208 * {@code BufferedReader}. 209 * 210 * @param in The input reader. 211 * @param length Specify a positive number if the length of the input is known. 212 * @param bufferSize Specify the buffer size to use. 213 * @return The contents of the reader as a string. <jk>null</jk> if reader was null. 214 * @throws IOException If a problem occurred trying to read from the reader. 215 */ 216 public static String read(Reader in, int length, int bufferSize) throws IOException { 217 if (in == null) 218 return null; 219 length = (length <= 0 ? bufferSize : length); 220 StringBuilder sb = new StringBuilder(length); // Assume they're ASCII characters. 221 try { 222 char[] buf = new char[Math.min(bufferSize, length)]; 223 int i = 0; 224 while ((i = in.read(buf)) != -1) 225 sb.append(buf, 0, i); 226 return sb.toString(); 227 } finally { 228 in.close(); 229 } 230 } 231 232 /** 233 * Pipes the contents of the specified reader into the writer. 234 * 235 * <p> 236 * The reader is closed, the writer is not. 237 * 238 * @param in 239 * The reader to pipe from. 240 * @param out 241 * The writer to pipe to. 242 * @throws IOException 243 */ 244 public static void pipe(Reader in, Writer out) throws IOException { 245 assertFieldNotNull(out, "out"); 246 assertFieldNotNull(in, "in"); 247 IOPipe.create(in, out).run(); 248 } 249 250 /** 251 * Pipes the contents of the specified object into the writer. 252 * 253 * <p> 254 * The reader is closed, the writer is not. 255 * 256 * @param in 257 * The input to pipe from. 258 * Can be any of the types defined by {@link #toReader(Object)}. 259 * @param out 260 * The writer to pipe to. 261 * @throws IOException 262 */ 263 public static void pipe(Object in, Writer out) throws IOException { 264 pipe(toReader(in), out); 265 } 266 267 /** 268 * Pipes the contents of the specified streams. 269 * 270 * <p> 271 * The input stream is closed, the output stream is not. 272 * 273 * @param in 274 * The reader to pipe from. 275 * @param out 276 * The writer to pipe to. 277 * @throws IOException 278 */ 279 public static void pipe(InputStream in, OutputStream out) throws IOException { 280 assertFieldNotNull(out, "out"); 281 assertFieldNotNull(in, "in"); 282 IOPipe.create(in, out).run(); 283 } 284 285 /** 286 * Pipes the contents of the specified object into the output stream. 287 * 288 * <p> 289 * The input stream is closed, the output stream is not. 290 * 291 * @param in 292 * The input to pipe from. 293 * Can be any of the types defined by {@link #toInputStream(Object)}. 294 * @param out 295 * The writer to pipe to. 296 * @throws IOException 297 */ 298 public static void pipe(Object in, OutputStream out) throws IOException { 299 pipe(toInputStream(in), out); 300 } 301 302 /** 303 * Wraps the specified reader in a buffered reader. 304 * 305 * @param r The reader being wrapped. 306 * @return 307 * The reader wrapped in a {@link BufferedReader}, or the original {@link Reader} if it's already a buffered 308 * reader. 309 */ 310 public static Reader getBufferedReader(Reader r) { 311 if (r == null || r instanceof BufferedReader || r instanceof StringReader) 312 return r; 313 return new BufferedReader(r); 314 } 315 316 /** 317 * Counts the number of bytes in the input stream and then closes the stream. 318 * 319 * @param is The input stream to read from. 320 * @return The number of bytes read. 321 * @throws IOException 322 */ 323 public static long count(InputStream is) throws IOException { 324 assertFieldNotNull(is, "is"); 325 long c = 0; 326 long i; 327 try { 328 while ((i = is.skip(1024)) != 0) 329 c += i; 330 } finally { 331 is.close(); 332 } 333 return c; 334 } 335 336 /** 337 * Counts the number of characters in the reader and then closes the reader. 338 * 339 * @param r The reader to read from. 340 * @return The number of characters read. 341 * @throws IOException 342 */ 343 public static long count(Reader r) throws IOException { 344 assertFieldNotNull(r, "r"); 345 long c = 0; 346 long i; 347 try { 348 while ((i = r.skip(1024)) != 0) 349 c += i; 350 } finally { 351 r.close(); 352 } 353 return c; 354 } 355 356 /** 357 * Given the specified <js>"Content-Length"</js> header value, return an appropriate buffer size. 358 * 359 * <p> 360 * The maximum buffer size is 1MB. 361 * 362 * @param contentLength The value of the <js>"Content-Length"</js> header. 363 * @return The appropriate buffer size. 364 */ 365 public static int getBufferSize(String contentLength) { 366 try { 367 if (! StringUtils.isEmpty(contentLength)) { 368 long l = Long.decode(contentLength); 369 if (l > 1048576) 370 return 1048576; 371 if (l <= 0) 372 return 8192; 373 return (int)l; 374 } 375 } catch (Exception e) { 376 return 8192; 377 } 378 return 8192; 379 } 380 381 /** 382 * Close input stream and ignore any exceptions. 383 * 384 * <p> 385 * No-op if input stream is <jk>null</jk>. 386 * 387 * @param is The input stream to close. 388 */ 389 public static void closeQuietly(InputStream is) { 390 try { 391 if (is != null) 392 is.close(); 393 } catch (IOException e) {} 394 } 395 396 /** 397 * Close output stream and ignore any exceptions. 398 * 399 * <p> 400 * No-op if output stream is <jk>null</jk>. 401 * 402 * @param os The output stream to close. 403 */ 404 public static void closeQuietly(OutputStream os) { 405 try { 406 if (os != null) 407 os.close(); 408 } catch (IOException e) {} 409 } 410 411 /** 412 * Close reader and ignore any exceptions. 413 * 414 * <p> 415 * No-op if reader is <jk>null</jk>. 416 * 417 * @param r The reader to close. 418 */ 419 public static void closeQuietly(Reader r) { 420 try { 421 if (r != null) 422 r.close(); 423 } catch (IOException e) {} 424 } 425 426 /** 427 * Close writer and ignore any exceptions. 428 * 429 * <p> 430 * No-op if writer is <jk>null</jk>. 431 * 432 * @param w The writer to close. 433 */ 434 public static void closeQuietly(Writer w) { 435 try { 436 if (w != null) 437 w.close(); 438 } catch (IOException e) {} 439 } 440 441 /** 442 * Quietly close all specified input streams, output streams, readers, and writers. 443 * 444 * @param o The list of all objects to quietly close. 445 */ 446 public static void closeQuietly(Object...o) { 447 for (Object o2 : o) { 448 if (o2 instanceof InputStream) 449 closeQuietly((InputStream)o2); 450 if (o2 instanceof OutputStream) 451 closeQuietly((OutputStream)o2); 452 if (o2 instanceof Reader) 453 closeQuietly((Reader)o2); 454 if (o2 instanceof Writer) 455 closeQuietly((Writer)o2); 456 } 457 } 458 459 /** 460 * Flushes multiple output streams and writers in a single call. 461 * 462 * @param o 463 * The objects to flush. 464 * <jk>null</jk> entries are ignored. 465 * @throws IOException 466 */ 467 public static void flush(Object...o) throws IOException { 468 IOException ex = null; 469 for (Object o2 : o) { 470 try { 471 if (o2 instanceof OutputStream) 472 ((OutputStream)o2).flush(); 473 if (o2 instanceof Writer) 474 ((Writer)o2).flush(); 475 } catch (IOException e) { 476 ex = e; 477 } 478 } 479 if (ex != null) 480 throw ex; 481 } 482 483 /** 484 * Close all specified input streams, output streams, readers, and writers. 485 * 486 * @param o 487 * The list of all objects to close. 488 * <jk>null</jk> entries are ignored. 489 * @throws IOException 490 */ 491 public static void close(Object...o) throws IOException { 492 IOException ex = null; 493 for (Object o2 : o) { 494 try { 495 if (o2 instanceof InputStream) 496 ((InputStream)o2).close(); 497 if (o2 instanceof OutputStream) 498 ((OutputStream)o2).close(); 499 if (o2 instanceof Reader) 500 ((Reader)o2).close(); 501 if (o2 instanceof Writer) 502 ((Writer)o2).close(); 503 } catch (IOException e) { 504 ex = e; 505 } 506 } 507 if (ex != null) 508 throw ex; 509 } 510 511 /** 512 * Converts an object to a <code>Reader</code>. 513 * 514 * @param o 515 * The object to convert to a reader. 516 * Can be any of the following: 517 * <ul> 518 * <li>{@link InputStream} 519 * <li>{@link Reader} 520 * <li>{@link File} 521 * <li>{@link CharSequence} 522 * <li><code><jk>byte</jk>[]</code> 523 * <li><code><jk>null</jk></code> - Returns <jk>null</jk>. 524 * </ul> 525 * @return The object converted to a reader. 526 * @throws IOException If file could not be read. 527 * @throws IllegalArgumentException If invalid object passed in. 528 */ 529 public static Reader toReader(Object o) throws IOException { 530 if (o == null) 531 return null; 532 if (o instanceof CharSequence) 533 return new StringReader(o.toString()); 534 if (o instanceof File) 535 return new FileReader((File)o); 536 if (o instanceof Reader) 537 return (Reader)o; 538 if (o instanceof InputStream) 539 return new InputStreamReader((InputStream)o, "UTF-8"); 540 if (o instanceof byte[]) 541 return new InputStreamReader(new ByteArrayInputStream((byte[])o), "UTF-8"); 542 throw new FormattedIllegalArgumentException("Invalid object of type {0} passed to IOUtils.toReader(Object)", o.getClass()); 543 } 544 545 /** 546 * Converts an object to an <code>InputStream</code>. 547 * 548 * @param o 549 * The object to convert to an input stream. 550 * Can be any of the following: 551 * <ul> 552 * <li>{@link InputStream} 553 * <li>{@link Reader} 554 * <li>{@link File} 555 * <li>{@link CharSequence} - Converted to UTF-8 stream. 556 * <li><code><jk>byte</jk>[]</code> 557 * <li><code><jk>null</jk></code> - Returns <jk>null</jk>. 558 * </ul> 559 * @return The object converted to an input stream. 560 * @throws IOException If file could not be read. 561 * @throws IllegalArgumentException If invalid object passed in. 562 */ 563 public static InputStream toInputStream(Object o) throws IOException { 564 if (o == null) 565 return null; 566 if (o instanceof InputStream) 567 return (InputStream)o; 568 if (o instanceof File) 569 return new FileInputStream((File)o); 570 if (o instanceof byte[]) 571 return new ByteArrayInputStream((byte[])o); 572 if (o instanceof CharSequence) 573 return new ByteArrayInputStream(((CharSequence)o).toString().getBytes(UTF8)); 574 if (o instanceof Reader) 575 return new ByteArrayInputStream(IOUtils.read((Reader)o).getBytes(UTF8)); 576 throw new FormattedIllegalArgumentException("Invalid object of type {0} passed to IOUtils.toInputStream(Object)", o.getClass()); 577 } 578}