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