1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 * 19 */ 20 21 package org.apache.directory.api.util; 22 23 24 import java.io.File; 25 import java.io.FileInputStream; 26 import java.io.FileNotFoundException; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.OutputStream; 31 import java.nio.channels.FileChannel; 32 import java.nio.charset.Charset; 33 import java.nio.file.Files; 34 import java.nio.file.Paths; 35 import java.nio.file.StandardOpenOption; 36 import java.util.List; 37 38 39 /** 40 * This code comes from Apache commons.io library. 41 * 42 * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. 43 * 44 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 45 */ 46 public final class FileUtils 47 { 48 /** 49 * The Windows separator character. 50 */ 51 private static final char WINDOWS_SEPARATOR = '\\'; 52 53 /** 54 * The system separator character. 55 */ 56 private static final char SYSTEM_SEPARATOR = File.separatorChar; 57 58 /** 59 * The number of bytes in a kilobyte. 60 */ 61 public static final long ONE_KB = 1024; 62 63 /** 64 * The number of bytes in a megabyte. 65 */ 66 public static final long ONE_MB = ONE_KB * ONE_KB; 67 68 /** 69 * The file copy buffer size (30 MB) 70 */ 71 private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30; 72 73 74 /** 75 * Creates a new instance of FileUtils. 76 */ 77 private FileUtils() 78 { 79 // Nothing to do. 80 } 81 82 83 /** 84 * Deletes a directory recursively. 85 * 86 * @param directory directory to delete 87 * @throws IOException in case deletion is unsuccessful 88 */ 89 public static void deleteDirectory( File directory ) throws IOException 90 { 91 if ( !directory.exists() ) 92 { 93 return; 94 } 95 96 if ( !isSymlink( directory ) ) 97 { 98 cleanDirectory( directory ); 99 } 100 101 if ( !directory.delete() ) 102 { 103 String message = "Unable to delete directory " + directory + "."; 104 throw new IOException( message ); 105 } 106 } 107 108 109 /** 110 * Determines whether the specified file is a Symbolic Link rather than an actual file. 111 * <p> 112 * Will not return true if there is a Symbolic Link anywhere in the path, 113 * only if the specific file is. 114 * <p> 115 * <b>Note:</b> the current implementation always returns {@code false} if the system 116 * is detected as Windows. 117 * <p> 118 * For code that runs on Java 1.7 or later, use the following method instead: 119 * <br> 120 * {@code boolean java.nio.file.Files.isSymbolicLink(Path path)} 121 * @param file the file to check 122 * @return true if the file is a Symbolic Link 123 * @throws IOException if an IO error occurs while checking the file 124 * @since 2.0 125 */ 126 public static boolean isSymlink( File file ) throws IOException 127 { 128 if ( file == null ) 129 { 130 throw new NullPointerException( "File must not be null" ); 131 } 132 133 if ( SYSTEM_SEPARATOR == WINDOWS_SEPARATOR ) 134 { 135 return false; 136 } 137 138 File fileInCanonicalDir = null; 139 140 if ( file.getParent() == null ) 141 { 142 fileInCanonicalDir = file; 143 } 144 else 145 { 146 File canonicalDir = file.getParentFile().getCanonicalFile(); 147 fileInCanonicalDir = new File( canonicalDir, file.getName() ); 148 } 149 150 return !fileInCanonicalDir.getCanonicalFile().equals( fileInCanonicalDir.getAbsoluteFile() ); 151 } 152 153 154 /** 155 * Deletes a directory recursively. 156 * 157 * @param directory directory to delete 158 * @throws IOException in case deletion is unsuccessful 159 */ 160 public static void cleanDirectory( File directory ) throws IOException 161 { 162 if ( !directory.exists() ) 163 { 164 String message = directory + " does not exist"; 165 throw new IllegalArgumentException( message ); 166 } 167 168 if ( !directory.isDirectory() ) 169 { 170 String message = directory + " is not a directory"; 171 throw new IllegalArgumentException( message ); 172 } 173 174 File[] files = directory.listFiles(); 175 176 if ( files == null ) 177 { 178 // null if security restricted 179 String message = "Failed to list contents of " + directory; 180 throw new IOException( message ); 181 } 182 183 IOException exception = null; 184 185 for ( File file : files ) 186 { 187 try 188 { 189 forceDelete( file ); 190 } 191 catch ( IOException ioe ) 192 { 193 exception = ioe; 194 } 195 } 196 197 if ( null != exception ) 198 { 199 throw exception; 200 } 201 } 202 203 204 /** 205 * Deletes a file. If file is a directory, delete it and all sub-directories. 206 * <p> 207 * The difference between File.delete() and this method are: 208 * <ul> 209 * <li>A directory to be deleted does not have to be empty.</li> 210 * <li>You get exceptions when a file or directory cannot be deleted. 211 * (java.io.File methods returns a boolean)</li> 212 * </ul> 213 * 214 * @param file file or directory to delete, must not be {@code null} 215 * @throws NullPointerException if the directory is {@code null} 216 * @throws FileNotFoundException if the file was not found 217 * @throws IOException in case deletion is unsuccessful 218 */ 219 public static void forceDelete( File file ) throws IOException 220 { 221 if ( file.isDirectory() ) 222 { 223 deleteDirectory( file ); 224 } 225 else 226 { 227 boolean filePresent = file.exists(); 228 229 if ( !file.delete() ) 230 { 231 if ( !filePresent ) 232 { 233 String message = "File does not exist: " + file; 234 throw new FileNotFoundException( message ); 235 } 236 237 String message = "Unable to delete file: " + file; 238 throw new IOException( message ); 239 } 240 } 241 } 242 243 244 /** 245 * Returns the path to the system temporary directory. 246 * 247 * @return the path to the system temporary directory. 248 * 249 * @since 2.0 250 */ 251 public static String getTempDirectoryPath() 252 { 253 return System.getProperty( "java.io.tmpdir" ); 254 } 255 256 257 /** 258 * Reads the contents of a file into a String using the default encoding for the VM. 259 * The file is always closed. 260 * 261 * @param file the file to read, must not be {@code null} 262 * @return the file contents, never {@code null} 263 * @throws IOException in case of an I/O error 264 * @since 1.3.1 265 * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead 266 */ 267 @Deprecated 268 public static String readFileToString( File file ) throws IOException 269 { 270 return readFileToString( file, Charset.defaultCharset() ); 271 } 272 273 274 /** 275 * Reads the contents of a file into a String. 276 * The file is always closed. 277 * 278 * @param file the file to read, must not be {@code null} 279 * @param encoding the encoding to use, {@code null} means platform default 280 * @return the file contents, never {@code null} 281 * @throws IOException in case of an I/O error 282 * @since 2.3 283 */ 284 public static String readFileToString( File file, Charset encoding ) throws IOException 285 { 286 InputStream in = null; 287 288 try 289 { 290 in = openInputStream( file ); 291 return IOUtils.toString( in, IOUtils.toCharset( encoding ) ); 292 } 293 finally 294 { 295 IOUtils.closeQuietly( in ); 296 } 297 } 298 299 300 /** 301 * Reads the contents of a file into a String. The file is always closed. 302 * 303 * @param file the file to read, must not be {@code null} 304 * @param encoding the encoding to use, {@code null} means platform default 305 * @return the file contents, never {@code null} 306 * @throws IOException in case of an I/O error 307 * @since 2.3 308 */ 309 public static String readFileToString( File file, String encoding ) throws IOException 310 { 311 InputStream in = null; 312 313 try 314 { 315 in = openInputStream( file ); 316 return IOUtils.toString( in, IOUtils.toCharset( encoding ) ); 317 } 318 finally 319 { 320 IOUtils.closeQuietly( in ); 321 } 322 } 323 324 325 /** 326 * Opens a {@link FileInputStream} for the specified file, providing better 327 * error messages than simply calling <code>new FileInputStream(file)</code>. 328 * <p> 329 * At the end of the method either the stream will be successfully opened, 330 * or an exception will have been thrown. 331 * <p> 332 * An exception is thrown if the file does not exist. 333 * An exception is thrown if the file object exists but is a directory. 334 * An exception is thrown if the file exists but cannot be read. 335 * 336 * @param file the file to open for input, must not be {@code null} 337 * @return a new {@link FileInputStream} for the specified file 338 * @throws FileNotFoundException if the file does not exist 339 * @throws IOException if the file object is a directory 340 * @throws IOException if the file cannot be read 341 * @since 1.3 342 */ 343 public static InputStream openInputStream( File file ) throws IOException 344 { 345 if ( file.exists() ) 346 { 347 if ( file.isDirectory() ) 348 { 349 throw new IOException( "File '" + file + "' exists but is a directory" ); 350 } 351 352 if ( !file.canRead() ) 353 { 354 throw new IOException( "File '" + file + "' cannot be read" ); 355 } 356 } 357 else 358 { 359 throw new FileNotFoundException( "File '" + file + "' does not exist" ); 360 } 361 362 return Files.newInputStream( Paths.get( file.getPath() ) ); 363 } 364 365 366 /** 367 * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. 368 * 369 * @param file the file to write 370 * @param data the content to write to the file 371 * @throws IOException in case of an I/O error 372 * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset, boolean)} instead 373 */ 374 @Deprecated 375 public static void writeStringToFile( File file, String data ) throws IOException 376 { 377 writeStringToFile( file, data, Charset.defaultCharset(), false ); 378 } 379 380 381 /** 382 * Writes a String to a file creating the file if it does not exist. 383 * 384 * NOTE: As from v1.3, the parent directories of the file will be created 385 * if they do not exist. 386 * 387 * @param file the file to write 388 * @param data the content to write to the file 389 * @param encoding the encoding to use, {@code null} means platform default 390 * @throws IOException in case of an I/O error 391 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 392 */ 393 public static void writeStringToFile( File file, String data, String encoding ) throws IOException 394 { 395 writeStringToFile( file, data, IOUtils.toCharset( encoding ), false ); 396 } 397 398 399 /** 400 * Writes a String to a file creating the file if it does not exist. 401 * 402 * @param file the file to write 403 * @param data the content to write to the file 404 * @param encoding the encoding to use, {@code null} means platform default 405 * @param append if {@code true}, then the String will be added to the 406 * end of the file rather than overwriting 407 * @throws IOException in case of an I/O error 408 * @since 2.3 409 */ 410 public static void writeStringToFile( File file, String data, Charset encoding, boolean append ) throws IOException 411 { 412 OutputStream out = null; 413 414 try 415 { 416 out = openOutputStream( file, append ); 417 IOUtils.write( data, out, encoding ); 418 out.close(); // don't swallow close Exception if copy completes normally 419 } 420 finally 421 { 422 IOUtils.closeQuietly( out ); 423 } 424 } 425 426 427 /** 428 * Opens a {@link FileOutputStream} for the specified file, checking and 429 * creating the parent directory if it does not exist. 430 * <p> 431 * At the end of the method either the stream will be successfully opened, 432 * or an exception will have been thrown. 433 * <p> 434 * The parent directory will be created if it does not exist. 435 * The file will be created if it does not exist. 436 * An exception is thrown if the file object exists but is a directory. 437 * An exception is thrown if the file exists but cannot be written to. 438 * An exception is thrown if the parent directory cannot be created. 439 * 440 * @param file the file to open for output, must not be {@code null} 441 * @param append if {@code true}, then bytes will be added to the 442 * end of the file rather than overwriting 443 * @return a new {@link FileOutputStream} for the specified file 444 * @throws IOException if the file object is a directory 445 * @throws IOException if the file cannot be written to 446 * @throws IOException if a parent directory needs creating but that fails 447 * @since 2.1 448 */ 449 public static OutputStream openOutputStream( File file, boolean append ) throws IOException 450 { 451 if ( file.exists() ) 452 { 453 if ( file.isDirectory() ) 454 { 455 throw new IOException( "File '" + file + "' exists but is a directory" ); 456 } 457 458 if ( !file.canWrite() ) 459 { 460 throw new IOException( "File '" + file + "' cannot be written to" ); 461 } 462 } 463 else 464 { 465 File parent = file.getParentFile(); 466 467 if ( parent != null ) 468 { 469 if ( !parent.mkdirs() && !parent.isDirectory() ) 470 { 471 throw new IOException( "Directory '" + parent + "' could not be created" ); 472 } 473 } 474 } 475 476 if ( append ) 477 { 478 return Files.newOutputStream( Paths.get( file.getPath() ), StandardOpenOption.CREATE, StandardOpenOption.APPEND ); 479 } 480 else 481 { 482 return Files.newOutputStream( Paths.get( file.getPath() ) ); 483 } 484 } 485 486 487 /** 488 * Returns a {@link File} representing the system temporary directory. 489 * 490 * @return the system temporary directory. 491 * 492 * @since 2.0 493 */ 494 public static File getTempDirectory() 495 { 496 return new File( getTempDirectoryPath() ); 497 } 498 499 500 /** 501 * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. 502 * <p> 503 * The difference between File.delete() and this method are: 504 * <ul> 505 * <li>A directory to be deleted does not have to be empty.</li> 506 * <li>No exceptions are thrown when a file or directory cannot be deleted.</li> 507 * </ul> 508 * 509 * @param file file or directory to delete, can be {@code null} 510 * @return {@code true} if the file or directory was deleted, otherwise 511 * {@code false} 512 * 513 * @since 1.4 514 */ 515 public static boolean deleteQuietly( File file ) 516 { 517 if ( file == null ) 518 { 519 return false; 520 } 521 522 try 523 { 524 if ( file.isDirectory() ) 525 { 526 cleanDirectory( file ); 527 } 528 } 529 catch ( Exception ignored ) 530 { 531 } 532 533 try 534 { 535 return file.delete(); 536 } 537 catch ( Exception ignored ) 538 { 539 return false; 540 } 541 } 542 543 544 /** 545 * Copies a file to a new location preserving the file date. 546 * <p> 547 * This method copies the contents of the specified source file to the 548 * specified destination file. The directory holding the destination file is 549 * created if it does not exist. If the destination file exists, then this 550 * method will overwrite it. 551 * <p> 552 * <strong>Note:</strong> This method tries to preserve the file's last 553 * modified date/times using {@link File#setLastModified(long)}, however 554 * it is not guaranteed that the operation will succeed. 555 * If the modification operation fails, no indication is provided. 556 * 557 * @param srcFile an existing file to copy, must not be {@code null} 558 * @param destFile the new file, must not be {@code null} 559 * 560 * @throws NullPointerException if source or destination is {@code null} 561 * @throws IOException if source or destination is invalid 562 * @throws IOException if an IO error occurs during copying 563 * @throws IOException if the output file length is not the same as the input file length after the copy completes 564 * @see #copyFile(File, File, boolean) 565 */ 566 public static void copyFile( File srcFile, File destFile ) throws IOException 567 { 568 copyFile( srcFile, destFile, true ); 569 } 570 571 572 /** 573 * Copies a file to a new location. 574 * <p> 575 * This method copies the contents of the specified source file 576 * to the specified destination file. 577 * The directory holding the destination file is created if it does not exist. 578 * If the destination file exists, then this method will overwrite it. 579 * <p> 580 * <strong>Note:</strong> Setting <code>preserveFileDate</code> to 581 * {@code true} tries to preserve the file's last modified 582 * date/times using {@link File#setLastModified(long)}, however it is 583 * not guaranteed that the operation will succeed. 584 * If the modification operation fails, no indication is provided. 585 * 586 * @param srcFile an existing file to copy, must not be {@code null} 587 * @param destFile the new file, must not be {@code null} 588 * @param preserveFileDate true if the file date of the copy 589 * should be the same as the original 590 * 591 * @throws NullPointerException if source or destination is {@code null} 592 * @throws IOException if source or destination is invalid 593 * @throws IOException if an IO error occurs during copying 594 * @throws IOException if the output file length is not the same as the input file length after the copy completes 595 */ 596 public static void copyFile( File srcFile, File destFile, boolean preserveFileDate ) throws IOException 597 { 598 if ( srcFile == null ) 599 { 600 throw new NullPointerException( "Source must not be null" ); 601 } 602 603 if ( destFile == null ) 604 { 605 throw new NullPointerException( "Destination must not be null" ); 606 } 607 608 if ( !srcFile.exists() ) 609 { 610 throw new FileNotFoundException( "Source '" + srcFile + "' does not exist" ); 611 } 612 613 if ( srcFile.isDirectory() ) 614 { 615 throw new IOException( "Source '" + srcFile + "' exists but is a directory" ); 616 } 617 618 if ( srcFile.getCanonicalPath().equals( destFile.getCanonicalPath() ) ) 619 { 620 throw new IOException( "Source '" + srcFile + "' and destination '" + destFile + "' are the same" ); 621 } 622 623 File parentFile = destFile.getParentFile(); 624 625 if ( parentFile != null ) 626 { 627 if ( !parentFile.mkdirs() && !parentFile.isDirectory() ) 628 { 629 throw new IOException( "Destination '" + parentFile + "' directory cannot be created" ); 630 } 631 } 632 633 if ( destFile.exists() && !destFile.canWrite() ) 634 { 635 throw new IOException( "Destination '" + destFile + "' exists but is read-only" ); 636 } 637 638 doCopyFile( srcFile, destFile, preserveFileDate ); 639 } 640 641 642 /** 643 * Internal copy file method. 644 * This caches the original file length, and throws an IOException 645 * if the output file length is different from the current input file length. 646 * So it may fail if the file changes size. 647 * It may also fail with "IllegalArgumentException: Negative size" if the input file is truncated part way 648 * through copying the data and the new file size is less than the current position. 649 * 650 * @param srcFile the validated source file, must not be {@code null} 651 * @param destFile the validated destination file, must not be {@code null} 652 * @param preserveFileDate whether to preserve the file date 653 * @throws IOException if an error occurs 654 * @throws IOException if the output file length is not the same as the input file length after the copy completes 655 * @throws IllegalArgumentException "Negative size" if the file is truncated so that the size is less than the position 656 */ 657 private static void doCopyFile( File srcFile, File destFile, boolean preserveFileDate ) throws IOException 658 { 659 if ( destFile.exists() && destFile.isDirectory() ) 660 { 661 throw new IOException( "Destination '" + destFile + "' exists but is a directory" ); 662 } 663 664 FileInputStream fis = null; 665 FileOutputStream fos = null; 666 FileChannel input = null; 667 FileChannel output = null; 668 669 try 670 { 671 fis = ( FileInputStream ) Files.newInputStream( Paths.get( srcFile.getPath() ) ); 672 fos = ( FileOutputStream ) Files.newOutputStream( Paths.get( destFile.getPath() ) ); 673 input = fis.getChannel(); 674 output = fos.getChannel(); 675 long size = input.size(); // TODO See IO-386 676 long pos = 0; 677 long count = 0; 678 679 while ( pos < size ) 680 { 681 long remain = size - pos; 682 count = remain > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : remain; 683 long bytesCopied = output.transferFrom( input, pos, count ); 684 685 if ( bytesCopied == 0 ) 686 { // IO-385 - can happen if file is truncated after caching the size 687 break; // ensure we don't loop forever 688 } 689 690 pos += bytesCopied; 691 } 692 } 693 finally 694 { 695 IOUtils.closeQuietly( output, fos, input, fis ); 696 } 697 698 long srcLen = srcFile.length(); // TODO See IO-386 699 long dstLen = destFile.length(); // TODO See IO-386 700 701 if ( srcLen != dstLen ) 702 { 703 throw new IOException( "Failed to copy full contents from '" 704 + srcFile + "' to '" + destFile + "' Expected length: " + srcLen + " Actual: " + dstLen ); 705 } 706 707 if ( preserveFileDate ) 708 { 709 destFile.setLastModified( srcFile.lastModified() ); 710 } 711 } 712 713 714 /** 715 * Writes a byte array to a file creating the file if it does not exist. 716 * <p> 717 * NOTE: As from v1.3, the parent directories of the file will be created 718 * if they do not exist. 719 * 720 * @param file the file to write to 721 * @param data the content to write to the file 722 * @throws IOException in case of an I/O erroe 723 * @since 1.1 724 */ 725 public static void writeByteArrayToFile( final File file, final byte[] data ) throws IOException 726 { 727 writeByteArrayToFile( file, data, false ); 728 } 729 730 731 /** 732 * Writes a byte array to a file creating the file if it does not exist. 733 * 734 * @param file the file to write to 735 * @param data the content to write to the file 736 * @param append if {@code true}, then bytes will be added to the 737 * end of the file rather than overwriting 738 * @throws IOException in case of an I/O error 739 * @since 2.1 740 */ 741 public static void writeByteArrayToFile( File file, byte[] data, boolean append ) throws IOException 742 { 743 writeByteArrayToFile( file, data, 0, data.length, append ); 744 } 745 746 747 /** 748 * Writes {@code len} bytes from the specified byte array starting 749 * at offset {@code off} to a file, creating the file if it does 750 * not exist. 751 * 752 * @param file the file to write to 753 * @param data the content to write to the file 754 * @param off the start offset in the data 755 * @param len the number of bytes to write 756 * @param append if {@code true}, then bytes will be added to the 757 * end of the file rather than overwriting 758 * @throws IOException in case of an I/O error 759 * @since 2.5 760 */ 761 public static void writeByteArrayToFile( File file, byte[] data, int off, int len, boolean append ) throws IOException 762 { 763 OutputStream out = null; 764 765 try 766 { 767 out = openOutputStream( file, append ); 768 out.write( data, off, len ); 769 out.close(); // don't swallow close Exception if copy completes normally 770 } 771 finally 772 { 773 IOUtils.closeQuietly( out ); 774 } 775 } 776 777 778 /** 779 * Reads the contents of a file into a byte array. 780 * The file is always closed. 781 * 782 * @param file the file to read, must not be {@code null} 783 * @return the file contents, never {@code null} 784 * @throws IOException in case of an I/O error 785 * @since 1.1 786 */ 787 public static byte[] readFileToByteArray( File file ) throws IOException 788 { 789 InputStream in = null; 790 791 try 792 { 793 in = openInputStream( file ); 794 return IOUtils.toByteArray( in, file.length() ); 795 } 796 finally 797 { 798 IOUtils.closeQuietly( in ); 799 } 800 } 801 802 803 /** 804 * Opens a {@link FileOutputStream} for the specified file, checking and 805 * creating the parent directory if it does not exist. 806 * <p> 807 * At the end of the method either the stream will be successfully opened, 808 * or an exception will have been thrown. 809 * <p> 810 * The parent directory will be created if it does not exist. 811 * The file will be created if it does not exist. 812 * An exception is thrown if the file object exists but is a directory. 813 * An exception is thrown if the file exists but cannot be written to. 814 * An exception is thrown if the parent directory cannot be created. 815 * 816 * @param file the file to open for output, must not be {@code null} 817 * @return a new {@link FileOutputStream} for the specified file 818 * @throws IOException if the file object is a directory 819 * @throws IOException if the file cannot be written to 820 * @throws IOException if a parent directory needs creating but that fails 821 * @since 1.3 822 */ 823 public static OutputStream openOutputStream( File file ) throws IOException 824 { 825 return openOutputStream( file, false ); 826 } 827 828 829 /** 830 * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. 831 * The file is always closed. 832 * 833 * @param file the file to read, must not be {@code null} 834 * @return the list of Strings representing each line in the file, never {@code null} 835 * @throws IOException in case of an I/O error 836 * @since 1.3 837 * @deprecated 2.5 use {@link #readLines(File, Charset)} instead 838 */ 839 @Deprecated 840 public static List<String> readLines( File file ) throws IOException 841 { 842 return readLines( file, Charset.defaultCharset() ); 843 } 844 845 846 /** 847 * Reads the contents of a file line by line to a List of Strings. 848 * The file is always closed. 849 * 850 * @param file the file to read, must not be {@code null} 851 * @param encoding the encoding to use, {@code null} means platform default 852 * @return the list of Strings representing each line in the file, never {@code null} 853 * @throws IOException in case of an I/O error 854 * @since 2.3 855 */ 856 public static List<String> readLines( File file, Charset encoding ) throws IOException 857 { 858 InputStream in = null; 859 860 try 861 { 862 in = openInputStream( file ); 863 return IOUtils.readLines( in, IOUtils.toCharset( encoding ) ); 864 } 865 finally 866 { 867 IOUtils.closeQuietly( in ); 868 } 869 } 870 }