001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 021package org.apache.directory.api.util; 022 023 024import java.io.BufferedReader; 025import java.io.Closeable; 026import java.io.IOException; 027import java.io.InputStream; 028import java.io.InputStreamReader; 029import java.io.OutputStream; 030import java.io.Reader; 031import java.io.Writer; 032import java.nio.charset.Charset; 033import java.util.ArrayList; 034import java.util.List; 035 036import org.apache.directory.api.i18n.I18n; 037 038 039/** 040 * This code comes from Apache commons.io library. 041 * 042 * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public final class IOUtils 047{ 048 /** 049 * The default buffer size ({@value}) to use for 050 * {@link #copyLarge(InputStream, OutputStream)} 051 * and 052 * {@link #copyLarge(Reader, Writer)} 053 */ 054 private static final int DEFAULT_BUFFER_SIZE = 1024 * 4; 055 056 /** The end of file */ 057 private static final int EOF = -1; 058 059 060 /** 061 * Creates a new instance of FileUtils. 062 */ 063 private IOUtils() 064 { 065 // Nothing to do. 066 } 067 068 069 /** 070 * Closes an <code>InputStream</code> unconditionally. 071 * <p> 072 * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. 073 * This is typically used in finally blocks. 074 * <p> 075 * Example code: 076 * <pre> 077 * byte[] data = new byte[1024]; 078 * InputStream in = null; 079 * try { 080 * in = new FileInputStream("foo.txt"); 081 * in.read(data); 082 * in.close(); //close errors are handled 083 * } catch (Exception e) { 084 * // error handling 085 * } finally { 086 * IOUtils.closeQuietly(in); 087 * } 088 * </pre> 089 * 090 * @param input the InputStream to close, may be null or already closed 091 */ 092 public static void closeQuietly( InputStream input ) 093 { 094 closeQuietly( ( Closeable ) input ); 095 } 096 097 098 /** 099 * Closes a <code>Closeable</code> unconditionally. 100 * <p> 101 * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in 102 * finally blocks. 103 * <p> 104 * Example code: 105 * 106 * <pre> 107 * Closeable closeable = null; 108 * try { 109 * closeable = new FileReader("foo.txt"); 110 * // process closeable 111 * closeable.close(); 112 * } catch (Exception e) { 113 * // error handling 114 * } finally { 115 * IOUtils.closeQuietly(closeable); 116 * } 117 * </pre> 118 * 119 * Closing all streams: 120 * 121 * <pre> 122 * try { 123 * return IOUtils.copy(inputStream, outputStream); 124 * } finally { 125 * IOUtils.closeQuietly(inputStream); 126 * IOUtils.closeQuietly(outputStream); 127 * } 128 * </pre> 129 * 130 * @param closeables the objects to close, may be null or already closed 131 * @since 2.5 132 */ 133 public static void closeQuietly( Closeable... closeables ) 134 { 135 if ( closeables == null ) 136 { 137 return; 138 } 139 140 for ( Closeable closeable : closeables ) 141 { 142 closeQuietly( closeable ); 143 } 144 } 145 146 147 /** 148 * Closes a <code>Closeable</code> unconditionally. 149 * <p> 150 * Equivalent to {@link Closeable#close()}, except any exceptions will be ignored. This is typically used in 151 * finally blocks. 152 * <p> 153 * Example code: 154 * 155 * <pre> 156 * Closeable closeable = null; 157 * try { 158 * closeable = new FileReader("foo.txt"); 159 * // process closeable 160 * closeable.close(); 161 * } catch (Exception e) { 162 * // error handling 163 * } finally { 164 * IOUtils.closeQuietly(closeable); 165 * } 166 * </pre> 167 * 168 * Closing all streams: 169 * 170 * <pre> 171 * try { 172 * return IOUtils.copy(inputStream, outputStream); 173 * } finally { 174 * IOUtils.closeQuietly(inputStream); 175 * IOUtils.closeQuietly(outputStream); 176 * } 177 * </pre> 178 * 179 * @param closeable 180 * the objects to close, may be null or already closed 181 * @since 2.0 182 */ 183 public static void closeQuietly( Closeable closeable ) 184 { 185 try 186 { 187 if ( closeable != null ) 188 { 189 closeable.close(); 190 } 191 } 192 catch ( IOException ioe ) 193 { 194 // ignore 195 } 196 } 197 198 199 /** 200 * Gets the contents of an <code>InputStream</code> as a String 201 * using the specified character encoding. 202 * <p> 203 * This method buffers the input internally, so there is no need to use a 204 * <code>BufferedInputStream</code>. 205 * </p> 206 * @param input the <code>InputStream</code> to read from 207 * @param encoding the encoding to use, null means platform default 208 * @return the requested String 209 * @throws NullPointerException if the input is null 210 * @throws IOException if an I/O error occurs 211 * @since 2.3 212 */ 213 public static String toString( InputStream input, Charset encoding ) throws IOException 214 { 215 StringBuilderWriter sw = new StringBuilderWriter(); 216 copy( input, sw, encoding ); 217 218 return sw.toString(); 219 } 220 221 222 /** 223 * Returns the given Charset or the default Charset if the given Charset is null. 224 * 225 * @param charset A charset or null. 226 * @return the given Charset or the default Charset if the given Charset is null 227 */ 228 public static Charset toCharset( Charset charset ) 229 { 230 return charset == null ? Charset.defaultCharset() : charset; 231 } 232 233 234 /** 235 * Returns a Charset for the named charset. If the name is null, return the default Charset. 236 * 237 * @param charset The name of the requested charset, may be null. 238 * @return a Charset for the named charset 239 */ 240 public static Charset toCharset( String charset ) 241 { 242 return charset == null ? Charset.defaultCharset() : Charset.forName( charset ); 243 } 244 245 246 /** 247 * Copies bytes from an <code>InputStream</code> to chars on a 248 * <code>Writer</code> using the specified character encoding. 249 * <p> 250 * This method buffers the input internally, so there is no need to use a 251 * <code>BufferedInputStream</code>. 252 * <p> 253 * This method uses {@link InputStreamReader}. 254 * 255 * @param input the <code>InputStream</code> to read from 256 * @param output the <code>Writer</code> to write to 257 * @param inputEncoding the encoding to use for the input stream, null means platform default 258 * @throws NullPointerException if the input or output is null 259 * @throws IOException if an I/O error occurs 260 * @since 2.3 261 */ 262 public static void copy( InputStream input, Writer output, Charset inputEncoding ) throws IOException 263 { 264 InputStreamReader in = new InputStreamReader( input, toCharset( inputEncoding ) ); 265 copy( in, output ); 266 } 267 268 269 /** 270 * Copies chars from a <code>Reader</code> to a <code>Writer</code>. 271 * <p> 272 * This method buffers the input internally, so there is no need to use a 273 * <code>BufferedReader</code>. 274 * <p> 275 * Large streams (over 2GB) will return a chars copied value of 276 * <code>-1</code> after the copy has completed since the correct 277 * number of chars cannot be returned as an int. For large streams 278 * use the <code>copyLarge(Reader, Writer)</code> method. 279 * 280 * @param input the <code>Reader</code> to read from 281 * @param output the <code>Writer</code> to write to 282 * @return the number of characters copied, or -1 if > Integer.MAX_VALUE 283 * @throws NullPointerException if the input or output is null 284 * @throws IOException if an I/O error occurs 285 * @since 1.1 286 */ 287 public static int copy( Reader input, Writer output ) throws IOException 288 { 289 long count = copyLarge( input, output ); 290 291 if ( count > Integer.MAX_VALUE ) 292 { 293 return -1; 294 } 295 296 return ( int ) count; 297 } 298 299 300 /** 301 * Copies bytes from an <code>InputStream</code> to an 302 * <code>OutputStream</code>. 303 * <p> 304 * This method buffers the input internally, so there is no need to use a 305 * <code>BufferedInputStream</code>. 306 * <p> 307 * Large streams (over 2GB) will return a bytes copied value of 308 * <code>-1</code> after the copy has completed since the correct 309 * number of bytes cannot be returned as an int. For large streams 310 * use the <code>copyLarge(InputStream, OutputStream)</code> method. 311 * 312 * @param input the <code>InputStream</code> to read from 313 * @param output the <code>OutputStream</code> to write to 314 * @return the number of bytes copied, or -1 if > Integer.MAX_VALUE 315 * @throws NullPointerException if the input or output is null 316 * @throws IOException if an I/O error occurs 317 * @since 1.1 318 */ 319 public static int copy( InputStream input, OutputStream output ) throws IOException 320 { 321 long count = copyLarge( input, output ); 322 323 if ( count > Integer.MAX_VALUE ) 324 { 325 return -1; 326 } 327 328 return ( int ) count; 329 } 330 331 332 /** 333 * Copies bytes from an <code>InputStream</code> to an <code>OutputStream</code> using an internal buffer of the 334 * given size. 335 * <p> 336 * This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>. 337 * <p> 338 * 339 * @param input 340 * the <code>InputStream</code> to read from 341 * @param output 342 * the <code>OutputStream</code> to write to 343 * @param bufferSize 344 * the bufferSize used to copy from the input to the output 345 * @return the number of bytes copied 346 * @throws NullPointerException 347 * if the input or output is null 348 * @throws IOException 349 * if an I/O error occurs 350 * @since 2.5 351 */ 352 public static long copy( InputStream input, OutputStream output, int bufferSize ) throws IOException 353 { 354 return copyLarge( input, output, new byte[bufferSize] ); 355 } 356 357 358 /** 359 * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>. 360 * <p> 361 * This method buffers the input internally, so there is no need to use a 362 * <code>BufferedReader</code>. 363 * <p> 364 * The buffer size is given by #DEFAULT_BUFFER_SIZE. 365 * 366 * @param input the <code>Reader</code> to read from 367 * @param output the <code>Writer</code> to write to 368 * @return the number of characters copied 369 * @throws NullPointerException if the input or output is null 370 * @throws IOException if an I/O error occurs 371 * @since 1.3 372 */ 373 public static long copyLarge( Reader input, Writer output ) throws IOException 374 { 375 return copyLarge( input, output, new char[DEFAULT_BUFFER_SIZE] ); 376 } 377 378 379 /** 380 * Copies bytes from a large (over 2GB) <code>InputStream</code> to an 381 * <code>OutputStream</code>. 382 * <p> 383 * This method buffers the input internally, so there is no need to use a 384 * <code>BufferedInputStream</code>. 385 * <p> 386 * The buffer size is given by #DEFAULT_BUFFER_SIZE. 387 * 388 * @param input the <code>InputStream</code> to read from 389 * @param output the <code>OutputStream</code> to write to 390 * @return the number of bytes copied 391 * @throws NullPointerException if the input or output is null 392 * @throws IOException if an I/O error occurs 393 * @since 1.3 394 */ 395 public static long copyLarge( InputStream input, OutputStream output ) throws IOException 396 { 397 return copy( input, output, DEFAULT_BUFFER_SIZE ); 398 } 399 400 401 /** 402 * Copies bytes from a large (over 2GB) <code>InputStream</code> to an 403 * <code>OutputStream</code>. 404 * <p> 405 * This method uses the provided buffer, so there is no need to use a 406 * <code>BufferedInputStream</code>. 407 * <p> 408 * 409 * @param input the <code>InputStream</code> to read from 410 * @param output the <code>OutputStream</code> to write to 411 * @param buffer the buffer to use for the copy 412 * @return the number of bytes copied 413 * @throws NullPointerException if the input or output is null 414 * @throws IOException if an I/O error occurs 415 * @since 2.2 416 */ 417 public static long copyLarge( InputStream input, OutputStream output, byte[] buffer ) throws IOException 418 { 419 long count = 0; 420 int n; 421 422 while ( EOF != ( n = input.read( buffer ) ) ) 423 { 424 output.write( buffer, 0, n ); 425 count += n; 426 } 427 428 return count; 429 } 430 431 432 /** 433 * Copies chars from a large (over 2GB) <code>Reader</code> to a <code>Writer</code>. 434 * <p> 435 * This method uses the provided buffer, so there is no need to use a 436 * <code>BufferedReader</code>. 437 * <p> 438 * 439 * @param input the <code>Reader</code> to read from 440 * @param output the <code>Writer</code> to write to 441 * @param buffer the buffer to be used for the copy 442 * @return the number of characters copied 443 * @throws NullPointerException if the input or output is null 444 * @throws IOException if an I/O error occurs 445 * @since 2.2 446 */ 447 public static long copyLarge( Reader input, Writer output, char[] buffer ) throws IOException 448 { 449 long count = 0; 450 int n; 451 452 while ( EOF != ( n = input.read( buffer ) ) ) 453 { 454 output.write( buffer, 0, n ); 455 count += n; 456 } 457 458 return count; 459 } 460 461 462 /** 463 * Writes chars from a <code>String</code> to bytes on an 464 * <code>OutputStream</code> using the specified character encoding. 465 * <p> 466 * This method uses {@link String#getBytes(String)}. 467 * 468 * @param data the <code>String</code> to write, null ignored 469 * @param output the <code>OutputStream</code> to write to 470 * @param encoding the encoding to use, null means platform default 471 * @throws NullPointerException if output is null 472 * @throws IOException if an I/O error occurs 473 * @since 2.3 474 */ 475 public static void write( String data, OutputStream output, Charset encoding ) throws IOException 476 { 477 if ( data != null ) 478 { 479 output.write( data.getBytes( toCharset( encoding ) ) ); 480 } 481 } 482 483 484 /** 485 * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>. 486 * Use this method instead of <code>toByteArray(InputStream)</code> 487 * when <code>InputStream</code> size is known 488 * @param input the <code>InputStream</code> to read from 489 * @param size the size of <code>InputStream</code> 490 * @return the requested byte array 491 * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size 492 * @throws IllegalArgumentException if size is less than zero 493 * @since 2.1 494 */ 495 public static byte[] toByteArray( InputStream input, int size ) throws IOException 496 { 497 if ( size < 0 ) 498 { 499 throw new IllegalArgumentException( I18n.err( I18n.ERR_17070_SIZE_POSITIVE, size ) ); 500 } 501 502 if ( size == 0 ) 503 { 504 return new byte[0]; 505 } 506 507 byte[] data = new byte[size]; 508 int offset = 0; 509 int readed = input.read( data, offset, size - offset ); 510 511 while ( offset < size && ( readed != EOF ) ) 512 { 513 offset += readed; 514 readed = input.read( data, offset, size - offset ); 515 } 516 517 if ( offset != size ) 518 { 519 throw new IOException( I18n.err( I18n.ERR_17071_UNEXPECTED_SIZE, offset, size ) ); 520 } 521 522 return data; 523 } 524 525 526 /** 527 * Gets contents of an <code>InputStream</code> as a <code>byte[]</code>. 528 * Use this method instead of <code>toByteArray(InputStream)</code> 529 * when <code>InputStream</code> size is known. 530 * <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation 531 * before using {@link IOUtils#toByteArray(java.io.InputStream, int)} to read into the byte array. 532 * (Arrays can have no more than Integer.MAX_VALUE entries anyway) 533 * 534 * @param input the <code>InputStream</code> to read from 535 * @param size the size of <code>InputStream</code> 536 * @return the requested byte array 537 * @throws IOException if an I/O error occurs or <code>InputStream</code> size differ from parameter size 538 * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE 539 * @see IOUtils#toByteArray(java.io.InputStream, int) 540 * @since 2.1 541 */ 542 public static byte[] toByteArray( InputStream input, long size ) throws IOException 543 { 544 545 if ( size > Integer.MAX_VALUE ) 546 { 547 throw new IllegalArgumentException( I18n.err( I18n.ERR_17072_INTEGER_OVERFLOW, size ) ); 548 } 549 550 return toByteArray( input, ( int ) size ); 551 } 552 553 554 /** 555 * Gets the contents of an <code>InputStream</code> as a list of Strings, 556 * one entry per line, using the specified character encoding. 557 * <p> 558 * This method buffers the input internally, so there is no need to use a 559 * <code>BufferedInputStream</code>. 560 * 561 * @param input the <code>InputStream</code> to read from, not null 562 * @param encoding the encoding to use, null means platform default 563 * @return the list of Strings, never null 564 * @throws NullPointerException if the input is null 565 * @throws IOException if an I/O error occurs 566 * @since 2.3 567 */ 568 public static List<String> readLines( InputStream input, Charset encoding ) throws IOException 569 { 570 InputStreamReader reader = new InputStreamReader( input, toCharset( encoding ) ); 571 572 return readLines( reader ); 573 } 574 575 576 /** 577 * Gets the contents of a <code>Reader</code> as a list of Strings, 578 * one entry per line. 579 * <p> 580 * This method buffers the input internally, so there is no need to use a 581 * <code>BufferedReader</code>. 582 * 583 * @param input the <code>Reader</code> to read from, not null 584 * @return the list of Strings, never null 585 * @throws NullPointerException if the input is null 586 * @throws IOException if an I/O error occurs 587 * @since 1.1 588 */ 589 public static List<String> readLines( Reader input ) throws IOException 590 { 591 BufferedReader reader = toBufferedReader( input ); 592 List<String> list = new ArrayList<>(); 593 String line = reader.readLine(); 594 595 while ( line != null ) 596 { 597 list.add( line ); 598 line = reader.readLine(); 599 } 600 601 return list; 602 } 603 604 605 /** 606 * Returns the given reader if it is a {@link BufferedReader}, otherwise creates a BufferedReader from the given 607 * reader. 608 * 609 * @param reader 610 * the reader to wrap or return (not null) 611 * @return the given reader or a new {@link BufferedReader} for the given reader 612 * @since 2.2 613 * @throws NullPointerException if the input parameter is null 614 */ 615 public static BufferedReader toBufferedReader( Reader reader ) 616 { 617 return reader instanceof BufferedReader ? ( BufferedReader ) reader : new BufferedReader( reader ); 618 } 619}