1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io; 18 19 import java.io.BufferedInputStream; 20 import java.io.BufferedOutputStream; 21 import java.io.File; 22 import java.io.FileFilter; 23 import java.io.FileInputStream; 24 import java.io.FileNotFoundException; 25 import java.io.FileOutputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.io.InputStreamReader; 29 import java.io.OutputStream; 30 import java.io.Reader; 31 import java.io.UncheckedIOException; 32 import java.math.BigInteger; 33 import java.net.URL; 34 import java.nio.ByteBuffer; 35 import java.nio.charset.Charset; 36 import java.nio.charset.StandardCharsets; 37 import java.nio.charset.UnsupportedCharsetException; 38 import java.nio.file.CopyOption; 39 import java.nio.file.DirectoryStream; 40 import java.nio.file.FileVisitOption; 41 import java.nio.file.FileVisitResult; 42 import java.nio.file.Files; 43 import java.nio.file.LinkOption; 44 import java.nio.file.NotDirectoryException; 45 import java.nio.file.Path; 46 import java.nio.file.StandardCopyOption; 47 import java.nio.file.attribute.BasicFileAttributeView; 48 import java.nio.file.attribute.BasicFileAttributes; 49 import java.nio.file.attribute.FileTime; 50 import java.time.Duration; 51 import java.time.Instant; 52 import java.time.LocalTime; 53 import java.time.OffsetDateTime; 54 import java.time.OffsetTime; 55 import java.time.ZoneId; 56 import java.time.chrono.ChronoLocalDate; 57 import java.time.chrono.ChronoLocalDateTime; 58 import java.time.chrono.ChronoZonedDateTime; 59 import java.util.ArrayList; 60 import java.util.Collection; 61 import java.util.Collections; 62 import java.util.Date; 63 import java.util.HashSet; 64 import java.util.Iterator; 65 import java.util.List; 66 import java.util.Objects; 67 import java.util.Set; 68 import java.util.stream.Collectors; 69 import java.util.stream.Stream; 70 import java.util.zip.CRC32; 71 import java.util.zip.CheckedInputStream; 72 import java.util.zip.Checksum; 73 74 import org.apache.commons.io.file.AccumulatorPathVisitor; 75 import org.apache.commons.io.file.Counters; 76 import org.apache.commons.io.file.PathFilter; 77 import org.apache.commons.io.file.PathUtils; 78 import org.apache.commons.io.file.StandardDeleteOption; 79 import org.apache.commons.io.filefilter.FileEqualsFileFilter; 80 import org.apache.commons.io.filefilter.FileFileFilter; 81 import org.apache.commons.io.filefilter.IOFileFilter; 82 import org.apache.commons.io.filefilter.SuffixFileFilter; 83 import org.apache.commons.io.filefilter.TrueFileFilter; 84 import org.apache.commons.io.function.IOConsumer; 85 import org.apache.commons.io.function.Uncheck; 86 87 /** 88 * General file manipulation utilities. 89 * <p> 90 * Facilities are provided in the following areas: 91 * </p> 92 * <ul> 93 * <li>writing to a file 94 * <li>reading from a file 95 * <li>make a directory including parent directories 96 * <li>copying files and directories 97 * <li>deleting files and directories 98 * <li>converting to and from a URL 99 * <li>listing files and directories by filter and extension 100 * <li>comparing file content 101 * <li>file last changed date 102 * <li>calculating a checksum 103 * </ul> 104 * <p> 105 * Note that a specific charset should be specified whenever possible. Relying on the platform default means that the 106 * code is Locale-dependent. Only use the default if the files are known to always use the platform default. 107 * </p> 108 * <p> 109 * {@link SecurityException} are not documented in the Javadoc. 110 * </p> 111 * <p> 112 * Provenance: Excalibur, Alexandria, Commons-Utils 113 * </p> 114 */ 115 public class FileUtils { 116 117 /** 118 * The number of bytes in a kilobyte. 119 */ 120 public static final long ONE_KB = 1024; 121 122 /** 123 * The number of bytes in a kilobyte. 124 * 125 * @since 2.4 126 */ 127 public static final BigInteger ONE_KB_BI = BigInteger.valueOf(ONE_KB); 128 129 /** 130 * The number of bytes in a megabyte. 131 */ 132 public static final long ONE_MB = ONE_KB * ONE_KB; 133 134 /** 135 * The number of bytes in a megabyte. 136 * 137 * @since 2.4 138 */ 139 public static final BigInteger ONE_MB_BI = ONE_KB_BI.multiply(ONE_KB_BI); 140 141 /** 142 * The number of bytes in a gigabyte. 143 */ 144 public static final long ONE_GB = ONE_KB * ONE_MB; 145 146 /** 147 * The number of bytes in a gigabyte. 148 * 149 * @since 2.4 150 */ 151 public static final BigInteger ONE_GB_BI = ONE_KB_BI.multiply(ONE_MB_BI); 152 153 /** 154 * The number of bytes in a terabyte. 155 */ 156 public static final long ONE_TB = ONE_KB * ONE_GB; 157 158 /** 159 * The number of bytes in a terabyte. 160 * 161 * @since 2.4 162 */ 163 public static final BigInteger ONE_TB_BI = ONE_KB_BI.multiply(ONE_GB_BI); 164 165 /** 166 * The number of bytes in a petabyte. 167 */ 168 public static final long ONE_PB = ONE_KB * ONE_TB; 169 170 /** 171 * The number of bytes in a petabyte. 172 * 173 * @since 2.4 174 */ 175 public static final BigInteger ONE_PB_BI = ONE_KB_BI.multiply(ONE_TB_BI); 176 177 /** 178 * The number of bytes in an exabyte. 179 */ 180 public static final long ONE_EB = ONE_KB * ONE_PB; 181 182 /** 183 * The number of bytes in an exabyte. 184 * 185 * @since 2.4 186 */ 187 public static final BigInteger ONE_EB_BI = ONE_KB_BI.multiply(ONE_PB_BI); 188 189 /** 190 * The number of bytes in a zettabyte. 191 */ 192 public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB)); 193 194 /** 195 * The number of bytes in a yottabyte. 196 */ 197 public static final BigInteger ONE_YB = ONE_KB_BI.multiply(ONE_ZB); 198 199 /** 200 * An empty array of type {@link File}. 201 */ 202 public static final File[] EMPTY_FILE_ARRAY = {}; 203 204 /** 205 * Returns a human-readable version of the file size, where the input represents a specific number of bytes. 206 * <p> 207 * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the 208 * nearest GB boundary. 209 * </p> 210 * <p> 211 * Similarly for the 1MB and 1KB boundaries. 212 * </p> 213 * 214 * @param size the number of bytes 215 * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) 216 * @throws NullPointerException if the given {@link BigInteger} is {@code null}. 217 * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> 218 * @since 2.4 219 */ 220 // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? byteCountToDisplaySize(final BigInteger size)221 public static String byteCountToDisplaySize(final BigInteger size) { 222 Objects.requireNonNull(size, "size"); 223 final String displaySize; 224 225 if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) { 226 displaySize = size.divide(ONE_EB_BI) + " EB"; 227 } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) { 228 displaySize = size.divide(ONE_PB_BI) + " PB"; 229 } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) { 230 displaySize = size.divide(ONE_TB_BI) + " TB"; 231 } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { 232 displaySize = size.divide(ONE_GB_BI) + " GB"; 233 } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { 234 displaySize = size.divide(ONE_MB_BI) + " MB"; 235 } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { 236 displaySize = size.divide(ONE_KB_BI) + " KB"; 237 } else { 238 displaySize = size + " bytes"; 239 } 240 return displaySize; 241 } 242 243 /** 244 * Returns a human-readable version of the file size, where the input represents a specific number of bytes. 245 * <p> 246 * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the 247 * nearest GB boundary. 248 * </p> 249 * <p> 250 * Similarly for the 1MB and 1KB boundaries. 251 * </p> 252 * 253 * @param size the number of bytes 254 * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) 255 * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> 256 */ 257 // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? byteCountToDisplaySize(final long size)258 public static String byteCountToDisplaySize(final long size) { 259 return byteCountToDisplaySize(BigInteger.valueOf(size)); 260 } 261 262 /** 263 * Returns a human-readable version of the file size, where the input represents a specific number of bytes. 264 * <p> 265 * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the 266 * nearest GB boundary. 267 * </p> 268 * <p> 269 * Similarly for the 1MB and 1KB boundaries. 270 * </p> 271 * 272 * @param size the number of bytes 273 * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) 274 * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> 275 * @since 2.12.0 276 */ 277 // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? byteCountToDisplaySize(final Number size)278 public static String byteCountToDisplaySize(final Number size) { 279 return byteCountToDisplaySize(size.longValue()); 280 } 281 282 /** 283 * Computes the checksum of a file using the specified checksum object. Multiple files may be checked using one 284 * {@link Checksum} instance if desired simply by reusing the same checksum object. For example: 285 * 286 * <pre> 287 * long checksum = FileUtils.checksum(file, new CRC32()).getValue(); 288 * </pre> 289 * 290 * @param file the file to checksum, must not be {@code null} 291 * @param checksum the checksum object to be used, must not be {@code null} 292 * @return the checksum specified, updated with the content of the file 293 * @throws NullPointerException if the given {@link File} is {@code null}. 294 * @throws NullPointerException if the given {@link Checksum} is {@code null}. 295 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a file. 296 * @throws IOException if an IO error occurs reading the file. 297 * @since 1.3 298 */ checksum(final File file, final Checksum checksum)299 public static Checksum checksum(final File file, final Checksum checksum) throws IOException { 300 requireExistsChecked(file, "file"); 301 requireFile(file, "file"); 302 Objects.requireNonNull(checksum, "checksum"); 303 try (InputStream inputStream = new CheckedInputStream(Files.newInputStream(file.toPath()), checksum)) { 304 IOUtils.consume(inputStream); 305 } 306 return checksum; 307 } 308 309 /** 310 * Computes the checksum of a file using the CRC32 checksum routine. 311 * The value of the checksum is returned. 312 * 313 * @param file the file to checksum, must not be {@code null} 314 * @return the checksum value 315 * @throws NullPointerException if the given {@link File} is {@code null}. 316 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a file. 317 * @throws IOException if an IO error occurs reading the file. 318 * @since 1.3 319 */ checksumCRC32(final File file)320 public static long checksumCRC32(final File file) throws IOException { 321 return checksum(file, new CRC32()).getValue(); 322 } 323 324 /** 325 * Cleans a directory without deleting it. 326 * 327 * @param directory directory to clean 328 * @throws NullPointerException if the given {@link File} is {@code null}. 329 * @throws IllegalArgumentException if directory does not exist or is not a directory. 330 * @throws IOException if an I/O error occurs. 331 * @see #forceDelete(File) 332 */ cleanDirectory(final File directory)333 public static void cleanDirectory(final File directory) throws IOException { 334 IOConsumer.forAll(FileUtils::forceDelete, listFiles(directory, null)); 335 } 336 337 /** 338 * Cleans a directory without deleting it. 339 * 340 * @param directory directory to clean, must not be {@code null} 341 * @throws NullPointerException if the given {@link File} is {@code null}. 342 * @throws IllegalArgumentException if directory does not exist or is not a directory. 343 * @throws IOException if an I/O error occurs. 344 * @see #forceDeleteOnExit(File) 345 */ cleanDirectoryOnExit(final File directory)346 private static void cleanDirectoryOnExit(final File directory) throws IOException { 347 IOConsumer.forAll(FileUtils::forceDeleteOnExit, listFiles(directory, null)); 348 } 349 350 /** 351 * Tests whether the contents of two files are equal. 352 * <p> 353 * This method checks to see if the two files are different lengths or if they point to the same file, before 354 * resorting to byte-by-byte comparison of the contents. 355 * </p> 356 * 357 * @param file1 the first file 358 * @param file2 the second file 359 * @return true if the content of the files are equal or they both don't exist, false otherwise 360 * @throws IllegalArgumentException when an input is not a file. 361 * @throws IOException If an I/O error occurs. 362 * @see PathUtils#fileContentEquals(Path,Path) 363 */ contentEquals(final File file1, final File file2)364 public static boolean contentEquals(final File file1, final File file2) throws IOException { 365 if (file1 == null && file2 == null) { 366 return true; 367 } 368 if (file1 == null || file2 == null) { 369 return false; 370 } 371 final boolean file1Exists = file1.exists(); 372 if (file1Exists != file2.exists()) { 373 return false; 374 } 375 376 if (!file1Exists) { 377 // two not existing files are equal 378 return true; 379 } 380 381 requireFile(file1, "file1"); 382 requireFile(file2, "file2"); 383 384 if (file1.length() != file2.length()) { 385 // lengths differ, cannot be equal 386 return false; 387 } 388 389 if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { 390 // same file 391 return true; 392 } 393 394 return PathUtils.fileContentEquals(file1.toPath(), file2.toPath()); 395 } 396 397 /** 398 * Compares the contents of two files to determine if they are equal or not. 399 * <p> 400 * This method checks to see if the two files point to the same file, 401 * before resorting to line-by-line comparison of the contents. 402 * </p> 403 * 404 * @param file1 the first file 405 * @param file2 the second file 406 * @param charsetName the name of the requested charset. 407 * May be null, in which case the platform default is used 408 * @return true if the content of the files are equal or neither exists, 409 * false otherwise 410 * @throws IllegalArgumentException when an input is not a file. 411 * @throws IOException in case of an I/O error. 412 * @throws UnsupportedCharsetException If the named charset is unavailable (unchecked exception). 413 * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader) 414 * @since 2.2 415 */ contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName)416 public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName) 417 throws IOException { 418 if (file1 == null && file2 == null) { 419 return true; 420 } 421 if (file1 == null || file2 == null) { 422 return false; 423 } 424 final boolean file1Exists = file1.exists(); 425 if (file1Exists != file2.exists()) { 426 return false; 427 } 428 429 if (!file1Exists) { 430 // two not existing files are equal 431 return true; 432 } 433 434 requireFile(file1, "file1"); 435 requireFile(file2, "file2"); 436 437 if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { 438 // same file 439 return true; 440 } 441 442 final Charset charset = Charsets.toCharset(charsetName); 443 try (Reader input1 = new InputStreamReader(Files.newInputStream(file1.toPath()), charset); 444 Reader input2 = new InputStreamReader(Files.newInputStream(file2.toPath()), charset)) { 445 return IOUtils.contentEqualsIgnoreEOL(input1, input2); 446 } 447 } 448 449 /** 450 * Converts a Collection containing {@link File} instances into array 451 * representation. This is to account for the difference between 452 * File.listFiles() and FileUtils.listFiles(). 453 * 454 * @param files a Collection containing {@link File} instances 455 * @return an array of {@link File} 456 */ convertFileCollectionToFileArray(final Collection<File> files)457 public static File[] convertFileCollectionToFileArray(final Collection<File> files) { 458 return files.toArray(EMPTY_FILE_ARRAY); 459 } 460 461 /** 462 * Copies a whole directory to a new location preserving the file dates. 463 * <p> 464 * This method copies the specified directory and all its child directories and files to the specified destination. 465 * The destination is the new location and name of the directory. 466 * </p> 467 * <p> 468 * The destination directory is created if it does not exist. If the destination directory did exist, then this 469 * method merges the source with the destination, with the source taking precedence. 470 * </p> 471 * <p> 472 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 473 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 474 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 475 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 476 * </p> 477 * 478 * @param srcDir an existing directory to copy, must not be {@code null}. 479 * @param destDir the new directory, must not be {@code null}. 480 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 481 * @throws IllegalArgumentException if the source or destination is invalid. 482 * @throws FileNotFoundException if the source does not exist. 483 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 484 * @since 1.1 485 */ copyDirectory(final File srcDir, final File destDir)486 public static void copyDirectory(final File srcDir, final File destDir) throws IOException { 487 copyDirectory(srcDir, destDir, true); 488 } 489 490 /** 491 * Copies a whole directory to a new location. 492 * <p> 493 * This method copies the contents of the specified source directory to within the specified destination directory. 494 * </p> 495 * <p> 496 * The destination directory is created if it does not exist. If the destination directory did exist, then this 497 * method merges the source with the destination, with the source taking precedence. 498 * </p> 499 * <p> 500 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last 501 * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations 502 * will succeed. If the modification operation fails, the methods throws IOException. 503 * </p> 504 * 505 * @param srcDir an existing directory to copy, must not be {@code null}. 506 * @param destDir the new directory, must not be {@code null}. 507 * @param preserveFileDate true if the file date of the copy should be the same as the original. 508 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 509 * @throws IllegalArgumentException if the source or destination is invalid. 510 * @throws FileNotFoundException if the source does not exist. 511 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 512 * @since 1.1 513 */ copyDirectory(final File srcDir, final File destDir, final boolean preserveFileDate)514 public static void copyDirectory(final File srcDir, final File destDir, final boolean preserveFileDate) 515 throws IOException { 516 copyDirectory(srcDir, destDir, null, preserveFileDate); 517 } 518 519 /** 520 * Copies a filtered directory to a new location preserving the file dates. 521 * <p> 522 * This method copies the contents of the specified source directory to within the specified destination directory. 523 * </p> 524 * <p> 525 * The destination directory is created if it does not exist. If the destination directory did exist, then this 526 * method merges the source with the destination, with the source taking precedence. 527 * </p> 528 * <p> 529 * <strong>Note:</strong> This method tries to preserve the files' last modified date/times using 530 * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the 531 * modification operation fails, the methods throws IOException. 532 * </p> 533 * <b>Example: Copy directories only</b> 534 * 535 * <pre> 536 * // only copy the directory structure 537 * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY); 538 * </pre> 539 * 540 * <b>Example: Copy directories and txt files</b> 541 * 542 * <pre> 543 * // Create a filter for ".txt" files 544 * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); 545 * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); 546 * 547 * // Create a filter for either directories or ".txt" files 548 * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); 549 * 550 * // Copy using the filter 551 * FileUtils.copyDirectory(srcDir, destDir, filter); 552 * </pre> 553 * 554 * @param srcDir an existing directory to copy, must not be {@code null}. 555 * @param destDir the new directory, must not be {@code null}. 556 * @param filter the filter to apply, null means copy all directories and files should be the same as the original. 557 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 558 * @throws IllegalArgumentException if the source or destination is invalid. 559 * @throws FileNotFoundException if the source does not exist. 560 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 561 * @since 1.4 562 */ copyDirectory(final File srcDir, final File destDir, final FileFilter filter)563 public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter) 564 throws IOException { 565 copyDirectory(srcDir, destDir, filter, true); 566 } 567 568 /** 569 * Copies a filtered directory to a new location. 570 * <p> 571 * This method copies the contents of the specified source directory to within the specified destination directory. 572 * </p> 573 * <p> 574 * The destination directory is created if it does not exist. If the destination directory did exist, then this 575 * method merges the source with the destination, with the source taking precedence. 576 * </p> 577 * <p> 578 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 579 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 580 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 581 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 582 * </p> 583 * <b>Example: Copy directories only</b> 584 * 585 * <pre> 586 * // only copy the directory structure 587 * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false); 588 * </pre> 589 * 590 * <b>Example: Copy directories and txt files</b> 591 * 592 * <pre> 593 * // Create a filter for ".txt" files 594 * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); 595 * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); 596 * 597 * // Create a filter for either directories or ".txt" files 598 * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); 599 * 600 * // Copy using the filter 601 * FileUtils.copyDirectory(srcDir, destDir, filter, false); 602 * </pre> 603 * 604 * @param srcDir an existing directory to copy, must not be {@code null}. 605 * @param destDir the new directory, must not be {@code null}. 606 * @param filter the filter to apply, null means copy all directories and files. 607 * @param preserveFileDate true if the file date of the copy should be the same as the original. 608 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 609 * @throws IllegalArgumentException if the source or destination is invalid. 610 * @throws FileNotFoundException if the source does not exist. 611 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 612 * @since 1.4 613 */ copyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate)614 public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate) throws IOException { 615 copyDirectory(srcDir, destDir, filter, preserveFileDate, StandardCopyOption.REPLACE_EXISTING); 616 } 617 618 /** 619 * Copies a filtered directory to a new location. 620 * <p> 621 * This method copies the contents of the specified source directory to within the specified destination directory. 622 * </p> 623 * <p> 624 * The destination directory is created if it does not exist. If the destination directory did exist, then this 625 * method merges the source with the destination, with the source taking precedence. 626 * </p> 627 * <p> 628 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 629 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 630 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 631 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 632 * </p> 633 * <b>Example: Copy directories only</b> 634 * 635 * <pre> 636 * // only copy the directory structure 637 * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false); 638 * </pre> 639 * 640 * <b>Example: Copy directories and txt files</b> 641 * 642 * <pre> 643 * // Create a filter for ".txt" files 644 * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); 645 * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); 646 * 647 * // Create a filter for either directories or ".txt" files 648 * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); 649 * 650 * // Copy using the filter 651 * FileUtils.copyDirectory(srcDir, destDir, filter, false); 652 * </pre> 653 * 654 * @param srcDir an existing directory to copy, must not be {@code null} 655 * @param destDir the new directory, must not be {@code null} 656 * @param fileFilter the filter to apply, null means copy all directories and files 657 * @param preserveFileDate true if the file date of the copy should be the same as the original 658 * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}. 659 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 660 * @throws IllegalArgumentException if the source or destination is invalid. 661 * @throws FileNotFoundException if the source does not exist. 662 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 663 * @since 2.8.0 664 */ copyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final boolean preserveFileDate, final CopyOption... copyOptions)665 public static void copyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final boolean preserveFileDate, 666 final CopyOption... copyOptions) throws IOException { 667 requireFileCopy(srcDir, destDir); 668 requireDirectory(srcDir, "srcDir"); 669 requireCanonicalPathsNotEquals(srcDir, destDir); 670 671 // Cater for destination being directory within the source directory (see IO-141) 672 List<String> exclusionList = null; 673 final String srcDirCanonicalPath = srcDir.getCanonicalPath(); 674 final String destDirCanonicalPath = destDir.getCanonicalPath(); 675 if (destDirCanonicalPath.startsWith(srcDirCanonicalPath)) { 676 final File[] srcFiles = listFiles(srcDir, fileFilter); 677 if (srcFiles.length > 0) { 678 exclusionList = new ArrayList<>(srcFiles.length); 679 for (final File srcFile : srcFiles) { 680 exclusionList.add(new File(destDir, srcFile.getName()).getCanonicalPath()); 681 } 682 } 683 } 684 doCopyDirectory(srcDir, destDir, fileFilter, exclusionList, preserveFileDate, copyOptions); 685 } 686 687 /** 688 * Copies a directory to within another directory preserving the file dates. 689 * <p> 690 * This method copies the source directory and all its contents to a directory of the same name in the specified 691 * destination directory. 692 * </p> 693 * <p> 694 * The destination directory is created if it does not exist. If the destination directory did exist, then this 695 * method merges the source with the destination, with the source taking precedence. 696 * </p> 697 * <p> 698 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 699 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 700 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 701 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 702 * </p> 703 * 704 * @param sourceDir an existing directory to copy, must not be {@code null}. 705 * @param destinationDir the directory to place the copy in, must not be {@code null}. 706 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 707 * @throws IllegalArgumentException if the source or destination is invalid. 708 * @throws FileNotFoundException if the source does not exist. 709 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 710 * @since 1.2 711 */ copyDirectoryToDirectory(final File sourceDir, final File destinationDir)712 public static void copyDirectoryToDirectory(final File sourceDir, final File destinationDir) throws IOException { 713 requireDirectoryIfExists(sourceDir, "sourceDir"); 714 requireDirectoryIfExists(destinationDir, "destinationDir"); 715 copyDirectory(sourceDir, new File(destinationDir, sourceDir.getName()), true); 716 } 717 718 /** 719 * Copies a file to a new location preserving the file date. 720 * <p> 721 * This method copies the contents of the specified source file to the specified destination file. The directory 722 * holding the destination file is created if it does not exist. If the destination file exists, then this method 723 * will overwrite it. 724 * </p> 725 * <p> 726 * <strong>Note:</strong> This method tries to preserve the file's last modified date/times using 727 * {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is not guaranteed that the 728 * operation will succeed. If the modification operation fails it will fallback to 729 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 730 * </p> 731 * 732 * @param srcFile an existing file to copy, must not be {@code null}. 733 * @param destFile the new file, must not be {@code null}. 734 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 735 * @throws IOException if source or destination is invalid. 736 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 737 * @throws IOException if the output file length is not the same as the input file length after the copy completes. 738 * @see #copyFileToDirectory(File, File) 739 * @see #copyFile(File, File, boolean) 740 */ copyFile(final File srcFile, final File destFile)741 public static void copyFile(final File srcFile, final File destFile) throws IOException { 742 copyFile(srcFile, destFile, StandardCopyOption.REPLACE_EXISTING); 743 } 744 745 /** 746 * Copies an existing file to a new file location. 747 * <p> 748 * This method copies the contents of the specified source file to the specified destination file. The directory 749 * holding the destination file is created if it does not exist. If the destination file exists, then this method 750 * will overwrite it. 751 * </p> 752 * <p> 753 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 754 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 755 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 756 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 757 * </p> 758 * 759 * @param srcFile an existing file to copy, must not be {@code null}. 760 * @param destFile the new file, must not be {@code null}. 761 * @param preserveFileDate true if the file date of the copy should be the same as the original. 762 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 763 * @throws IOException if source or destination is invalid. 764 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 765 * @throws IOException if the output file length is not the same as the input file length after the copy completes 766 * @see #copyFile(File, File, boolean, CopyOption...) 767 */ copyFile(final File srcFile, final File destFile, final boolean preserveFileDate)768 public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException { 769 copyFile(srcFile, destFile, preserveFileDate, StandardCopyOption.REPLACE_EXISTING); 770 } 771 772 /** 773 * Copies a file to a new location. 774 * <p> 775 * This method copies the contents of the specified source file to the specified destination file. The directory 776 * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite 777 * it with {@link StandardCopyOption#REPLACE_EXISTING}. 778 * </p> 779 * <p> 780 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 781 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 782 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 783 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 784 * </p> 785 * 786 * @param srcFile an existing file to copy, must not be {@code null}. 787 * @param destFile the new file, must not be {@code null}. 788 * @param preserveFileDate true if the file date of the copy should be the same as the original. 789 * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. 790 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 791 * @throws FileNotFoundException if the source does not exist. 792 * @throws IllegalArgumentException if source is not a file. 793 * @throws IOException if the output file length is not the same as the input file length after the copy completes. 794 * @throws IOException if an I/O error occurs, or setting the last-modified time didn't succeed. 795 * @see #copyFileToDirectory(File, File, boolean) 796 * @since 2.8.0 797 */ copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions)798 public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException { 799 requireFileCopy(srcFile, destFile); 800 requireFile(srcFile, "srcFile"); 801 requireCanonicalPathsNotEquals(srcFile, destFile); 802 createParentDirectories(destFile); 803 requireFileIfExists(destFile, "destFile"); 804 if (destFile.exists()) { 805 requireCanWrite(destFile, "destFile"); 806 } 807 Files.copy(srcFile.toPath(), destFile.toPath(), copyOptions); 808 809 // On Windows, the last modified time is copied by default. 810 if (preserveFileDate && !setTimes(srcFile, destFile)) { 811 throw new IOException("Cannot set the file time."); 812 } 813 } 814 815 /** 816 * Copies a file to a new location. 817 * <p> 818 * This method copies the contents of the specified source file to the specified destination file. The directory 819 * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite 820 * it if you use {@link StandardCopyOption#REPLACE_EXISTING}. 821 * </p> 822 * 823 * @param srcFile an existing file to copy, must not be {@code null}. 824 * @param destFile the new file, must not be {@code null}. 825 * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. 826 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 827 * @throws FileNotFoundException if the source does not exist. 828 * @throws IllegalArgumentException if source is not a file. 829 * @throws IOException if an I/O error occurs. 830 * @see StandardCopyOption 831 * @since 2.9.0 832 */ copyFile(final File srcFile, final File destFile, final CopyOption... copyOptions)833 public static void copyFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException { 834 copyFile(srcFile, destFile, true, copyOptions); 835 } 836 837 /** 838 * Copies bytes from a {@link File} to an {@link OutputStream}. 839 * <p> 840 * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}. 841 * </p> 842 * 843 * @param input the {@link File} to read. 844 * @param output the {@link OutputStream} to write. 845 * @return the number of bytes copied 846 * @throws NullPointerException if the File is {@code null}. 847 * @throws NullPointerException if the OutputStream is {@code null}. 848 * @throws IOException if an I/O error occurs. 849 * @since 2.1 850 */ copyFile(final File input, final OutputStream output)851 public static long copyFile(final File input, final OutputStream output) throws IOException { 852 try (InputStream fis = Files.newInputStream(input.toPath())) { 853 return IOUtils.copyLarge(fis, output); 854 } 855 } 856 857 /** 858 * Copies a file to a directory preserving the file date. 859 * <p> 860 * This method copies the contents of the specified source file to a file of the same name in the specified 861 * destination directory. The destination directory is created if it does not exist. If the destination file exists, 862 * then this method will overwrite it. 863 * </p> 864 * <p> 865 * <strong>Note:</strong> This method tries to preserve the file's last modified date/times using 866 * {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is not guaranteed that the 867 * operation will succeed. If the modification operation fails it will fallback to 868 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 869 * </p> 870 * 871 * @param srcFile an existing file to copy, must not be {@code null}. 872 * @param destDir the directory to place the copy in, must not be {@code null}. 873 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 874 * @throws IllegalArgumentException if source or destination is invalid. 875 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 876 * @see #copyFile(File, File, boolean) 877 */ copyFileToDirectory(final File srcFile, final File destDir)878 public static void copyFileToDirectory(final File srcFile, final File destDir) throws IOException { 879 copyFileToDirectory(srcFile, destDir, true); 880 } 881 882 /** 883 * Copies a file to a directory optionally preserving the file date. 884 * <p> 885 * This method copies the contents of the specified source file to a file of the same name in the specified 886 * destination directory. The destination directory is created if it does not exist. If the destination file exists, 887 * then this method will overwrite it. 888 * </p> 889 * <p> 890 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 891 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 892 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 893 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 894 * </p> 895 * 896 * @param sourceFile an existing file to copy, must not be {@code null}. 897 * @param destinationDir the directory to place the copy in, must not be {@code null}. 898 * @param preserveFileDate true if the file date of the copy should be the same as the original. 899 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 900 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 901 * @throws IOException if the output file length is not the same as the input file length after the copy completes. 902 * @see #copyFile(File, File, CopyOption...) 903 * @since 1.3 904 */ copyFileToDirectory(final File sourceFile, final File destinationDir, final boolean preserveFileDate)905 public static void copyFileToDirectory(final File sourceFile, final File destinationDir, final boolean preserveFileDate) throws IOException { 906 Objects.requireNonNull(sourceFile, "sourceFile"); 907 requireDirectoryIfExists(destinationDir, "destinationDir"); 908 copyFile(sourceFile, new File(destinationDir, sourceFile.getName()), preserveFileDate); 909 } 910 911 /** 912 * Copies bytes from an {@link InputStream} {@code source} to a file 913 * {@code destination}. The directories up to {@code destination} 914 * will be created if they don't already exist. {@code destination} 915 * will be overwritten if it already exists. 916 * <p> 917 * <em>The {@code source} stream is closed.</em> 918 * </p> 919 * <p> 920 * See {@link #copyToFile(InputStream, File)} for a method that does not close the input stream. 921 * </p> 922 * 923 * @param source the {@link InputStream} to copy bytes from, must not be {@code null}, will be closed 924 * @param destination the non-directory {@link File} to write bytes to 925 * (possibly overwriting), must not be {@code null} 926 * @throws IOException if {@code destination} is a directory 927 * @throws IOException if {@code destination} cannot be written 928 * @throws IOException if {@code destination} needs creating but can't be 929 * @throws IOException if an IO error occurs during copying 930 * @since 2.0 931 */ copyInputStreamToFile(final InputStream source, final File destination)932 public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException { 933 try (InputStream inputStream = source) { 934 copyToFile(inputStream, destination); 935 } 936 } 937 938 /** 939 * Copies a file or directory to within another directory preserving the file dates. 940 * <p> 941 * This method copies the source file or directory, along all its contents, to a directory of the same name in the 942 * specified destination directory. 943 * </p> 944 * <p> 945 * The destination directory is created if it does not exist. If the destination directory did exist, then this method 946 * merges the source with the destination, with the source taking precedence. 947 * </p> 948 * <p> 949 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 950 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 951 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 952 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 953 * </p> 954 * 955 * @param sourceFile an existing file or directory to copy, must not be {@code null}. 956 * @param destinationDir the directory to place the copy in, must not be {@code null}. 957 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 958 * @throws IllegalArgumentException if the source or destination is invalid. 959 * @throws FileNotFoundException if the source does not exist. 960 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 961 * @see #copyDirectoryToDirectory(File, File) 962 * @see #copyFileToDirectory(File, File) 963 * @since 2.6 964 */ copyToDirectory(final File sourceFile, final File destinationDir)965 public static void copyToDirectory(final File sourceFile, final File destinationDir) throws IOException { 966 Objects.requireNonNull(sourceFile, "sourceFile"); 967 if (sourceFile.isFile()) { 968 copyFileToDirectory(sourceFile, destinationDir); 969 } else if (sourceFile.isDirectory()) { 970 copyDirectoryToDirectory(sourceFile, destinationDir); 971 } else { 972 throw new FileNotFoundException("The source " + sourceFile + " does not exist"); 973 } 974 } 975 976 /** 977 * Copies a files to a directory preserving each file's date. 978 * <p> 979 * This method copies the contents of the specified source files 980 * to a file of the same name in the specified destination directory. 981 * The destination directory is created if it does not exist. 982 * If the destination file exists, then this method will overwrite it. 983 * </p> 984 * <p> 985 * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last 986 * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}, however it is 987 * not guaranteed that the operation will succeed. If the modification operation fails it will fallback to 988 * {@link File#setLastModified(long)} and if that fails, the methods throws IOException. 989 * </p> 990 * 991 * @param sourceIterable existing files to copy, must not be {@code null}. 992 * @param destinationDir the directory to place the copies in, must not be {@code null}. 993 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 994 * @throws IOException if source or destination is invalid. 995 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 996 * @see #copyFileToDirectory(File, File) 997 * @since 2.6 998 */ copyToDirectory(final Iterable<File> sourceIterable, final File destinationDir)999 public static void copyToDirectory(final Iterable<File> sourceIterable, final File destinationDir) throws IOException { 1000 Objects.requireNonNull(sourceIterable, "sourceIterable"); 1001 for (final File src : sourceIterable) { 1002 copyFileToDirectory(src, destinationDir); 1003 } 1004 } 1005 1006 /** 1007 * Copies bytes from an {@link InputStream} source to a {@link File} destination. The directories 1008 * up to {@code destination} will be created if they don't already exist. {@code destination} will be 1009 * overwritten if it already exists. The {@code source} stream is left open, e.g. for use with 1010 * {@link java.util.zip.ZipInputStream ZipInputStream}. See {@link #copyInputStreamToFile(InputStream, File)} for a 1011 * method that closes the input stream. 1012 * 1013 * @param inputStream the {@link InputStream} to copy bytes from, must not be {@code null} 1014 * @param file the non-directory {@link File} to write bytes to (possibly overwriting), must not be 1015 * {@code null} 1016 * @throws NullPointerException if the InputStream is {@code null}. 1017 * @throws NullPointerException if the File is {@code null}. 1018 * @throws IllegalArgumentException if the file object is a directory. 1019 * @throws IllegalArgumentException if the file is not writable. 1020 * @throws IOException if the directories could not be created. 1021 * @throws IOException if an IO error occurs during copying. 1022 * @since 2.5 1023 */ copyToFile(final InputStream inputStream, final File file)1024 public static void copyToFile(final InputStream inputStream, final File file) throws IOException { 1025 try (OutputStream out = newOutputStream(file, false)) { 1026 IOUtils.copy(inputStream, out); 1027 } 1028 } 1029 1030 /** 1031 * Copies bytes from the URL {@code source} to a file 1032 * {@code destination}. The directories up to {@code destination} 1033 * will be created if they don't already exist. {@code destination} 1034 * will be overwritten if it already exists. 1035 * <p> 1036 * Warning: this method does not set a connection or read timeout and thus 1037 * might block forever. Use {@link #copyURLToFile(URL, File, int, int)} 1038 * with reasonable timeouts to prevent this. 1039 * </p> 1040 * 1041 * @param source the {@link URL} to copy bytes from, must not be {@code null} 1042 * @param destination the non-directory {@link File} to write bytes to 1043 * (possibly overwriting), must not be {@code null} 1044 * @throws IOException if {@code source} URL cannot be opened 1045 * @throws IOException if {@code destination} is a directory 1046 * @throws IOException if {@code destination} cannot be written 1047 * @throws IOException if {@code destination} needs creating but can't be 1048 * @throws IOException if an IO error occurs during copying 1049 */ copyURLToFile(final URL source, final File destination)1050 public static void copyURLToFile(final URL source, final File destination) throws IOException { 1051 final Path path = destination.toPath(); 1052 PathUtils.createParentDirectories(path); 1053 PathUtils.copy(source::openStream, path, StandardCopyOption.REPLACE_EXISTING); 1054 } 1055 1056 /** 1057 * Copies bytes from the URL {@code source} to a file {@code destination}. The directories up to 1058 * {@code destination} will be created if they don't already exist. {@code destination} will be 1059 * overwritten if it already exists. 1060 * 1061 * @param source the {@link URL} to copy bytes from, must not be {@code null} 1062 * @param destination the non-directory {@link File} to write bytes to (possibly overwriting), must not be 1063 * {@code null} 1064 * @param connectionTimeoutMillis the number of milliseconds until this method will time out if no connection could 1065 * be established to the {@code source} 1066 * @param readTimeoutMillis the number of milliseconds until this method will time out if no data could be read from 1067 * the {@code source} 1068 * @throws IOException if {@code source} URL cannot be opened 1069 * @throws IOException if {@code destination} is a directory 1070 * @throws IOException if {@code destination} cannot be written 1071 * @throws IOException if {@code destination} needs creating but can't be 1072 * @throws IOException if an IO error occurs during copying 1073 * @since 2.0 1074 */ copyURLToFile(final URL source, final File destination, final int connectionTimeoutMillis, final int readTimeoutMillis)1075 public static void copyURLToFile(final URL source, final File destination, final int connectionTimeoutMillis, final int readTimeoutMillis) 1076 throws IOException { 1077 try (CloseableURLConnection urlConnection = CloseableURLConnection.open(source)) { 1078 urlConnection.setConnectTimeout(connectionTimeoutMillis); 1079 urlConnection.setReadTimeout(readTimeoutMillis); 1080 try (InputStream stream = urlConnection.getInputStream()) { 1081 copyInputStreamToFile(stream, destination); 1082 } 1083 } 1084 } 1085 1086 /** 1087 * Creates all parent directories for a File object, including any necessary but non-existent parent directories. If a parent directory already exists or 1088 * is null, nothing happens. 1089 * 1090 * @param file the File that may need parents, may be null. 1091 * @return The parent directory, or {@code null} if the given File does have a parent. 1092 * @throws IOException if the directory was not created along with all its parent directories. 1093 * @throws SecurityException See {@link File#mkdirs()}. 1094 * @since 2.9.0 1095 */ createParentDirectories(final File file)1096 public static File createParentDirectories(final File file) throws IOException { 1097 return mkdirs(getParentFile(file)); 1098 } 1099 1100 /** 1101 * Gets the current directory. 1102 * 1103 * @return the current directory. 1104 * @since 2.12.0 1105 */ current()1106 public static File current() { 1107 return PathUtils.current().toFile(); 1108 } 1109 1110 /** 1111 * Decodes the specified URL as per RFC 3986, i.e. transforms 1112 * percent-encoded octets to characters by decoding with the UTF-8 character 1113 * set. This function is primarily intended for usage with 1114 * {@link java.net.URL} which unfortunately does not enforce proper URLs. As 1115 * such, this method will leniently accept invalid characters or malformed 1116 * percent-encoded octets and simply pass them literally through to the 1117 * result string. Except for rare edge cases, this will make unencoded URLs 1118 * pass through unaltered. 1119 * 1120 * @param url The URL to decode, may be {@code null}. 1121 * @return The decoded URL or {@code null} if the input was 1122 * {@code null}. 1123 */ decodeUrl(final String url)1124 static String decodeUrl(final String url) { 1125 String decoded = url; 1126 if (url != null && url.indexOf('%') >= 0) { 1127 final int n = url.length(); 1128 final StringBuilder builder = new StringBuilder(); 1129 final ByteBuffer byteBuffer = ByteBuffer.allocate(n); 1130 for (int i = 0; i < n; ) { 1131 if (url.charAt(i) == '%') { 1132 try { 1133 do { 1134 final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16); 1135 byteBuffer.put(octet); 1136 i += 3; 1137 } while (i < n && url.charAt(i) == '%'); 1138 continue; 1139 } catch (final RuntimeException ignored) { 1140 // malformed percent-encoded octet, fall through and 1141 // append characters literally 1142 } finally { 1143 if (byteBuffer.position() > 0) { 1144 byteBuffer.flip(); 1145 builder.append(StandardCharsets.UTF_8.decode(byteBuffer).toString()); 1146 byteBuffer.clear(); 1147 } 1148 } 1149 } 1150 builder.append(url.charAt(i++)); 1151 } 1152 decoded = builder.toString(); 1153 } 1154 return decoded; 1155 } 1156 1157 /** 1158 * Deletes the given File but throws an IOException if it cannot, unlike {@link File#delete()} which returns a 1159 * boolean. 1160 * 1161 * @param file The file to delete. 1162 * @return the given file. 1163 * @throws NullPointerException if the parameter is {@code null} 1164 * @throws IOException if the file cannot be deleted. 1165 * @see File#delete() 1166 * @since 2.9.0 1167 */ delete(final File file)1168 public static File delete(final File file) throws IOException { 1169 Objects.requireNonNull(file, "file"); 1170 Files.delete(file.toPath()); 1171 return file; 1172 } 1173 1174 /** 1175 * Deletes a directory recursively. 1176 * 1177 * @param directory directory to delete 1178 * @throws IOException in case deletion is unsuccessful 1179 * @throws NullPointerException if the parameter is {@code null} 1180 * @throws IllegalArgumentException if {@code directory} is not a directory 1181 */ deleteDirectory(final File directory)1182 public static void deleteDirectory(final File directory) throws IOException { 1183 Objects.requireNonNull(directory, "directory"); 1184 if (!directory.exists()) { 1185 return; 1186 } 1187 if (!isSymlink(directory)) { 1188 cleanDirectory(directory); 1189 } 1190 delete(directory); 1191 } 1192 1193 /** 1194 * Schedules a directory recursively for deletion on JVM exit. 1195 * 1196 * @param directory directory to delete, must not be {@code null} 1197 * @throws NullPointerException if the directory is {@code null} 1198 * @throws IOException in case deletion is unsuccessful 1199 */ deleteDirectoryOnExit(final File directory)1200 private static void deleteDirectoryOnExit(final File directory) throws IOException { 1201 if (!directory.exists()) { 1202 return; 1203 } 1204 directory.deleteOnExit(); 1205 if (!isSymlink(directory)) { 1206 cleanDirectoryOnExit(directory); 1207 } 1208 } 1209 1210 /** 1211 * Deletes a file, never throwing an exception. If file is a directory, delete it and all subdirectories. 1212 * <p> 1213 * The difference between File.delete() and this method are: 1214 * </p> 1215 * <ul> 1216 * <li>A directory to be deleted does not have to be empty.</li> 1217 * <li>No exceptions are thrown when a file or directory cannot be deleted.</li> 1218 * </ul> 1219 * 1220 * @param file file or directory to delete, can be {@code null} 1221 * @return {@code true} if the file or directory was deleted, otherwise 1222 * {@code false} 1223 * @since 1.4 1224 */ deleteQuietly(final File file)1225 public static boolean deleteQuietly(final File file) { 1226 if (file == null) { 1227 return false; 1228 } 1229 try { 1230 if (file.isDirectory()) { 1231 cleanDirectory(file); 1232 } 1233 } catch (final Exception ignored) { 1234 // ignore 1235 } 1236 1237 try { 1238 return file.delete(); 1239 } catch (final Exception ignored) { 1240 return false; 1241 } 1242 } 1243 1244 /** 1245 * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory). 1246 * <p> 1247 * Files are normalized before comparison. 1248 * </p> 1249 * 1250 * Edge cases: 1251 * <ul> 1252 * <li>A {@code directory} must not be null: if null, throw IllegalArgumentException</li> 1253 * <li>A {@code directory} must be a directory: if not a directory, throw IllegalArgumentException</li> 1254 * <li>A directory does not contain itself: return false</li> 1255 * <li>A null child file is not contained in any parent: return false</li> 1256 * </ul> 1257 * 1258 * @param directory the file to consider as the parent. 1259 * @param child the file to consider as the child. 1260 * @return true is the candidate leaf is under by the specified composite. False otherwise. 1261 * @throws IOException if an IO error occurs while checking the files. 1262 * @throws NullPointerException if the given {@link File} is {@code null}. 1263 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a directory. 1264 * @see FilenameUtils#directoryContains(String, String) 1265 * @since 2.2 1266 */ directoryContains(final File directory, final File child)1267 public static boolean directoryContains(final File directory, final File child) throws IOException { 1268 requireDirectoryExists(directory, "directory"); 1269 1270 if (child == null || !directory.exists() || !child.exists()) { 1271 return false; 1272 } 1273 1274 // Canonicalize paths (normalizes relative paths) 1275 return FilenameUtils.directoryContains(directory.getCanonicalPath(), child.getCanonicalPath()); 1276 } 1277 1278 /** 1279 * Internal copy directory method. Creates all destination parent directories, 1280 * including any necessary but non-existent parent directories. 1281 * 1282 * @param srcDir the validated source directory, must not be {@code null}. 1283 * @param destDir the validated destination directory, must not be {@code null}. 1284 * @param fileFilter the filter to apply, null means copy all directories and files. 1285 * @param exclusionList List of files and directories to exclude from the copy, may be null. 1286 * @param preserveDirDate preserve the directories last modified dates. 1287 * @param copyOptions options specifying how the copy should be done, see {@link StandardCopyOption}. 1288 * @throws IOException if the directory was not created along with all its parent directories. 1289 * @throws SecurityException See {@link File#mkdirs()}. 1290 */ doCopyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final List<String> exclusionList, final boolean preserveDirDate, final CopyOption... copyOptions)1291 private static void doCopyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final List<String> exclusionList, 1292 final boolean preserveDirDate, final CopyOption... copyOptions) throws IOException { 1293 // recurse dirs, copy files. 1294 final File[] srcFiles = listFiles(srcDir, fileFilter); 1295 requireDirectoryIfExists(destDir, "destDir"); 1296 mkdirs(destDir); 1297 requireCanWrite(destDir, "destDir"); 1298 for (final File srcFile : srcFiles) { 1299 final File dstFile = new File(destDir, srcFile.getName()); 1300 if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) { 1301 if (srcFile.isDirectory()) { 1302 doCopyDirectory(srcFile, dstFile, fileFilter, exclusionList, preserveDirDate, copyOptions); 1303 } else { 1304 copyFile(srcFile, dstFile, preserveDirDate, copyOptions); 1305 } 1306 } 1307 } 1308 // Do this last, as the above has probably affected directory metadata 1309 if (preserveDirDate) { 1310 setTimes(srcDir, destDir); 1311 } 1312 } 1313 1314 /** 1315 * Deletes a file or directory. For a directory, delete it and all subdirectories. 1316 * <p> 1317 * The difference between File.delete() and this method are: 1318 * </p> 1319 * <ul> 1320 * <li>The directory does not have to be empty.</li> 1321 * <li>You get an exception when a file or directory cannot be deleted.</li> 1322 * </ul> 1323 * 1324 * @param file file or directory to delete, must not be {@code null}. 1325 * @throws NullPointerException if the file is {@code null}. 1326 * @throws FileNotFoundException if the file was not found. 1327 * @throws IOException in case deletion is unsuccessful. 1328 */ forceDelete(final File file)1329 public static void forceDelete(final File file) throws IOException { 1330 Objects.requireNonNull(file, "file"); 1331 final Counters.PathCounters deleteCounters; 1332 try { 1333 deleteCounters = PathUtils.delete(file.toPath(), PathUtils.EMPTY_LINK_OPTION_ARRAY, 1334 StandardDeleteOption.OVERRIDE_READ_ONLY); 1335 } catch (final IOException e) { 1336 throw new IOException("Cannot delete file: " + file, e); 1337 } 1338 1339 if (deleteCounters.getFileCounter().get() < 1 && deleteCounters.getDirectoryCounter().get() < 1) { 1340 // didn't find a file to delete. 1341 throw new FileNotFoundException("File does not exist: " + file); 1342 } 1343 } 1344 1345 /** 1346 * Schedules a file to be deleted when JVM exits. 1347 * If file is directory delete it and all subdirectories. 1348 * 1349 * @param file file or directory to delete, must not be {@code null}. 1350 * @throws NullPointerException if the file is {@code null}. 1351 * @throws IOException in case deletion is unsuccessful. 1352 */ forceDeleteOnExit(final File file)1353 public static void forceDeleteOnExit(final File file) throws IOException { 1354 Objects.requireNonNull(file, "file"); 1355 if (file.isDirectory()) { 1356 deleteDirectoryOnExit(file); 1357 } else { 1358 file.deleteOnExit(); 1359 } 1360 } 1361 1362 /** 1363 * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is 1364 * null, nothing happens. 1365 * <p> 1366 * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure. 1367 * </p> 1368 * 1369 * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens. 1370 * @throws IOException if the directory was not created along with all its parent directories. 1371 * @throws IOException if the given file object is not a directory. 1372 * @throws SecurityException See {@link File#mkdirs()}. 1373 * @see File#mkdirs() 1374 */ forceMkdir(final File directory)1375 public static void forceMkdir(final File directory) throws IOException { 1376 mkdirs(directory); 1377 } 1378 1379 /** 1380 * Creates all directories for a File object, including any necessary but non-existent parent directories. If the parent directory already exists or is 1381 * null, nothing happens. 1382 * <p> 1383 * Calls {@link File#mkdirs()} for the parent of @{code file}. 1384 * </p> 1385 * 1386 * @param file file with parents to create, must not be {@code null}. 1387 * @throws NullPointerException if the file is {@code null}. 1388 * @throws IOException if the directory was not created along with all its parent directories. 1389 * @throws SecurityException See {@link File#mkdirs()}. 1390 * @see File#mkdirs() 1391 * @since 2.5 1392 */ forceMkdirParent(final File file)1393 public static void forceMkdirParent(final File file) throws IOException { 1394 forceMkdir(getParentFile(Objects.requireNonNull(file, "file"))); 1395 } 1396 1397 /** 1398 * Constructs a file from the set of name elements. 1399 * 1400 * @param directory the parent directory. 1401 * @param names the name elements. 1402 * @return the new file. 1403 * @since 2.1 1404 */ getFile(final File directory, final String... names)1405 public static File getFile(final File directory, final String... names) { 1406 Objects.requireNonNull(directory, "directory"); 1407 Objects.requireNonNull(names, "names"); 1408 File file = directory; 1409 for (final String name : names) { 1410 file = new File(file, name); 1411 } 1412 return file; 1413 } 1414 1415 /** 1416 * Constructs a file from the set of name elements. 1417 * 1418 * @param names the name elements. 1419 * @return the file. 1420 * @since 2.1 1421 */ getFile(final String... names)1422 public static File getFile(final String... names) { 1423 Objects.requireNonNull(names, "names"); 1424 File file = null; 1425 for (final String name : names) { 1426 if (file == null) { 1427 file = new File(name); 1428 } else { 1429 file = new File(file, name); 1430 } 1431 } 1432 return file; 1433 } 1434 1435 /** 1436 * Gets the parent of the given file. The given file may be null. Note that a file's parent may be null as well. 1437 * 1438 * @param file The file to query, may be null. 1439 * @return The parent file or {@code null}. Note that a file's parent may be null as well. 1440 */ getParentFile(final File file)1441 private static File getParentFile(final File file) { 1442 return file == null ? null : file.getParentFile(); 1443 } 1444 1445 /** 1446 * Returns a {@link File} representing the system temporary directory. 1447 * 1448 * @return the system temporary directory as a File 1449 * @since 2.0 1450 */ getTempDirectory()1451 public static File getTempDirectory() { 1452 return new File(getTempDirectoryPath()); 1453 } 1454 1455 /** 1456 * Returns the path to the system temporary directory. 1457 * 1458 * WARNING: this method relies on the Java system property 'java.io.tmpdir' 1459 * which may or may not have a trailing file separator. 1460 * This can affect code that uses String processing to manipulate pathnames rather 1461 * than the standard libary methods in classes such as {@link java.io.File} 1462 * 1463 * @return the path to the system temporary directory as a String 1464 * @since 2.0 1465 */ getTempDirectoryPath()1466 public static String getTempDirectoryPath() { 1467 return System.getProperty("java.io.tmpdir"); 1468 } 1469 1470 /** 1471 * Returns a {@link File} representing the user's home directory. 1472 * 1473 * @return the user's home directory. 1474 * @since 2.0 1475 */ getUserDirectory()1476 public static File getUserDirectory() { 1477 return new File(getUserDirectoryPath()); 1478 } 1479 1480 /** 1481 * Returns the path to the user's home directory. 1482 * 1483 * @return the path to the user's home directory. 1484 * @since 2.0 1485 */ getUserDirectoryPath()1486 public static String getUserDirectoryPath() { 1487 return System.getProperty("user.home"); 1488 } 1489 1490 /** 1491 * Tests whether the specified {@link File} is a directory or not. Implemented as a 1492 * null-safe delegate to {@link Files#isDirectory(Path path, LinkOption... options)}. 1493 * 1494 * @param file the path to the file. 1495 * @param options options indicating how symbolic links are handled 1496 * @return {@code true} if the file is a directory; {@code false} if 1497 * the path is null, the file does not exist, is not a directory, or it cannot 1498 * be determined if the file is a directory or not. 1499 * @throws SecurityException In the case of the default provider, and a security manager is installed, the 1500 * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read 1501 * access to the directory. 1502 * @since 2.9.0 1503 */ isDirectory(final File file, final LinkOption... options)1504 public static boolean isDirectory(final File file, final LinkOption... options) { 1505 return file != null && Files.isDirectory(file.toPath(), options); 1506 } 1507 1508 /** 1509 * Tests whether the directory is empty. 1510 * 1511 * @param directory the directory to query. 1512 * @return whether the directory is empty. 1513 * @throws IOException if an I/O error occurs. 1514 * @throws NotDirectoryException if the file could not otherwise be opened because it is not a directory 1515 * <i>(optional specific exception)</i>. 1516 * @since 2.9.0 1517 */ isEmptyDirectory(final File directory)1518 public static boolean isEmptyDirectory(final File directory) throws IOException { 1519 return PathUtils.isEmptyDirectory(directory.toPath()); 1520 } 1521 1522 /** 1523 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate} 1524 * at the end of day. 1525 * 1526 * <p>Note: The input date is assumed to be in the system default time-zone with the time 1527 * part set to the current time. To use a non-default time-zone use the method 1528 * {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) 1529 * isFileNewer(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where 1530 * {@code zoneId} is a valid {@link ZoneId}. 1531 * 1532 * @param file the {@link File} of which the modification date must be compared. 1533 * @param chronoLocalDate the date reference. 1534 * @return true if the {@link File} exists and has been modified after the given 1535 * {@link ChronoLocalDate} at the current time. 1536 * @throws NullPointerException if the file or local date is {@code null}. 1537 * @since 2.8.0 1538 */ isFileNewer(final File file, final ChronoLocalDate chronoLocalDate)1539 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate) { 1540 return isFileNewer(file, chronoLocalDate, LocalTime.MAX); 1541 } 1542 1543 /** 1544 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate} 1545 * at the specified time. 1546 * 1547 * <p>Note: The input date and time are assumed to be in the system default time-zone. To use a 1548 * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) 1549 * isFileNewer(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid 1550 * {@link ZoneId}. 1551 * 1552 * @param file the {@link File} of which the modification date must be compared. 1553 * @param chronoLocalDate the date reference. 1554 * @param localTime the time reference. 1555 * @return true if the {@link File} exists and has been modified after the given 1556 * {@link ChronoLocalDate} at the given time. 1557 * @throws NullPointerException if the file, local date or zone ID is {@code null}. 1558 * @since 2.8.0 1559 */ isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime)1560 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { 1561 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); 1562 Objects.requireNonNull(localTime, "localTime"); 1563 return isFileNewer(file, chronoLocalDate.atTime(localTime)); 1564 } 1565 1566 /** 1567 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate} at the specified 1568 * {@link OffsetTime}. 1569 * 1570 * @param file the {@link File} of which the modification date must be compared 1571 * @param chronoLocalDate the date reference 1572 * @param offsetTime the time reference 1573 * @return true if the {@link File} exists and has been modified after the given {@link ChronoLocalDate} at the given 1574 * {@link OffsetTime}. 1575 * @throws NullPointerException if the file, local date or zone ID is {@code null} 1576 * @since 2.12.0 1577 */ isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime)1578 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) { 1579 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); 1580 Objects.requireNonNull(offsetTime, "offsetTime"); 1581 return isFileNewer(file, chronoLocalDate.atTime(offsetTime.toLocalTime())); 1582 } 1583 1584 /** 1585 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDateTime} 1586 * at the system-default time zone. 1587 * 1588 * <p>Note: The input date and time is assumed to be in the system default time-zone. To use a 1589 * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) 1590 * isFileNewer(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid 1591 * {@link ZoneId}. 1592 * 1593 * @param file the {@link File} of which the modification date must be compared. 1594 * @param chronoLocalDateTime the date reference. 1595 * @return true if the {@link File} exists and has been modified after the given 1596 * {@link ChronoLocalDateTime} at the system-default time zone. 1597 * @throws NullPointerException if the file or local date time is {@code null}. 1598 * @since 2.8.0 1599 */ isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime)1600 public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) { 1601 return isFileNewer(file, chronoLocalDateTime, ZoneId.systemDefault()); 1602 } 1603 1604 /** 1605 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDateTime} 1606 * at the specified {@link ZoneId}. 1607 * 1608 * @param file the {@link File} of which the modification date must be compared. 1609 * @param chronoLocalDateTime the date reference. 1610 * @param zoneId the time zone. 1611 * @return true if the {@link File} exists and has been modified after the given 1612 * {@link ChronoLocalDateTime} at the given {@link ZoneId}. 1613 * @throws NullPointerException if the file, local date time or zone ID is {@code null}. 1614 * @since 2.8.0 1615 */ isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId)1616 public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) { 1617 Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); 1618 Objects.requireNonNull(zoneId, "zoneId"); 1619 return isFileNewer(file, chronoLocalDateTime.atZone(zoneId)); 1620 } 1621 1622 /** 1623 * Tests if the specified {@link File} is newer than the specified {@link ChronoZonedDateTime}. 1624 * 1625 * @param file the {@link File} of which the modification date must be compared. 1626 * @param chronoZonedDateTime the date reference. 1627 * @return true if the {@link File} exists and has been modified after the given 1628 * {@link ChronoZonedDateTime}. 1629 * @throws NullPointerException if the file or zoned date time is {@code null}. 1630 * @since 2.8.0 1631 */ isFileNewer(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime)1632 public static boolean isFileNewer(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) { 1633 Objects.requireNonNull(file, "file"); 1634 Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); 1635 return Uncheck.get(() -> PathUtils.isNewer(file.toPath(), chronoZonedDateTime)); 1636 } 1637 1638 /** 1639 * Tests if the specified {@link File} is newer than the specified {@link Date}. 1640 * 1641 * @param file the {@link File} of which the modification date must be compared. 1642 * @param date the date reference. 1643 * @return true if the {@link File} exists and has been modified 1644 * after the given {@link Date}. 1645 * @throws NullPointerException if the file or date is {@code null}. 1646 */ isFileNewer(final File file, final Date date)1647 public static boolean isFileNewer(final File file, final Date date) { 1648 Objects.requireNonNull(date, "date"); 1649 return isFileNewer(file, date.getTime()); 1650 } 1651 1652 /** 1653 * Tests if the specified {@link File} is newer than the reference {@link File}. 1654 * 1655 * @param file the {@link File} of which the modification date must be compared. 1656 * @param reference the {@link File} of which the modification date is used. 1657 * @return true if the {@link File} exists and has been modified more 1658 * recently than the reference {@link File}. 1659 * @throws NullPointerException if the file or reference file is {@code null}. 1660 * @throws IllegalArgumentException if the reference file doesn't exist. 1661 */ isFileNewer(final File file, final File reference)1662 public static boolean isFileNewer(final File file, final File reference) { 1663 requireExists(reference, "reference"); 1664 return Uncheck.get(() -> PathUtils.isNewer(file.toPath(), reference.toPath())); 1665 } 1666 1667 /** 1668 * Tests if the specified {@link File} is newer than the specified {@link FileTime}. 1669 * 1670 * @param file the {@link File} of which the modification date must be compared. 1671 * @param fileTime the file time reference. 1672 * @return true if the {@link File} exists and has been modified after the given {@link FileTime}. 1673 * @throws IOException if an I/O error occurs. 1674 * @throws NullPointerException if the file or local date is {@code null}. 1675 * @since 2.12.0 1676 */ isFileNewer(final File file, final FileTime fileTime)1677 public static boolean isFileNewer(final File file, final FileTime fileTime) throws IOException { 1678 Objects.requireNonNull(file, "file"); 1679 return PathUtils.isNewer(file.toPath(), fileTime); 1680 } 1681 1682 /** 1683 * Tests if the specified {@link File} is newer than the specified {@link Instant}. 1684 * 1685 * @param file the {@link File} of which the modification date must be compared. 1686 * @param instant the date reference. 1687 * @return true if the {@link File} exists and has been modified after the given {@link Instant}. 1688 * @throws NullPointerException if the file or instant is {@code null}. 1689 * @since 2.8.0 1690 */ isFileNewer(final File file, final Instant instant)1691 public static boolean isFileNewer(final File file, final Instant instant) { 1692 Objects.requireNonNull(instant, "instant"); 1693 return Uncheck.get(() -> PathUtils.isNewer(file.toPath(), instant)); 1694 } 1695 1696 /** 1697 * Tests if the specified {@link File} is newer than the specified time reference. 1698 * 1699 * @param file the {@link File} of which the modification date must be compared. 1700 * @param timeMillis the time reference measured in milliseconds since the 1701 * epoch (00:00:00 GMT, January 1, 1970). 1702 * @return true if the {@link File} exists and has been modified after the given time reference. 1703 * @throws NullPointerException if the file is {@code null}. 1704 */ isFileNewer(final File file, final long timeMillis)1705 public static boolean isFileNewer(final File file, final long timeMillis) { 1706 Objects.requireNonNull(file, "file"); 1707 return Uncheck.get(() -> PathUtils.isNewer(file.toPath(), timeMillis)); 1708 } 1709 1710 /** 1711 * Tests if the specified {@link File} is newer than the specified {@link OffsetDateTime}. 1712 * 1713 * @param file the {@link File} of which the modification date must be compared 1714 * @param offsetDateTime the date reference 1715 * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}. 1716 * @throws NullPointerException if the file or zoned date time is {@code null} 1717 * @since 2.12.0 1718 */ isFileNewer(final File file, final OffsetDateTime offsetDateTime)1719 public static boolean isFileNewer(final File file, final OffsetDateTime offsetDateTime) { 1720 Objects.requireNonNull(offsetDateTime, "offsetDateTime"); 1721 return isFileNewer(file, offsetDateTime.toInstant()); 1722 } 1723 1724 /** 1725 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate} 1726 * at the end of day. 1727 * 1728 * <p>Note: The input date is assumed to be in the system default time-zone with the time 1729 * part set to the current time. To use a non-default time-zone use the method 1730 * {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) 1731 * isFileOlder(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where 1732 * {@code zoneId} is a valid {@link ZoneId}. 1733 * 1734 * @param file the {@link File} of which the modification date must be compared. 1735 * @param chronoLocalDate the date reference. 1736 * @return true if the {@link File} exists and has been modified before the given 1737 * {@link ChronoLocalDate} at the current time. 1738 * @throws NullPointerException if the file or local date is {@code null}. 1739 * @see ZoneId#systemDefault() 1740 * @see LocalTime#now() 1741 * @since 2.8.0 1742 */ isFileOlder(final File file, final ChronoLocalDate chronoLocalDate)1743 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate) { 1744 return isFileOlder(file, chronoLocalDate, LocalTime.MAX); 1745 } 1746 1747 /** 1748 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate} 1749 * at the specified {@link LocalTime}. 1750 * 1751 * <p>Note: The input date and time are assumed to be in the system default time-zone. To use a 1752 * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) 1753 * isFileOlder(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid 1754 * {@link ZoneId}. 1755 * 1756 * @param file the {@link File} of which the modification date must be compared. 1757 * @param chronoLocalDate the date reference. 1758 * @param localTime the time reference. 1759 * @return true if the {@link File} exists and has been modified before the 1760 * given {@link ChronoLocalDate} at the specified time. 1761 * @throws NullPointerException if the file, local date or local time is {@code null}. 1762 * @see ZoneId#systemDefault() 1763 * @since 2.8.0 1764 */ isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime)1765 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { 1766 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); 1767 Objects.requireNonNull(localTime, "localTime"); 1768 return isFileOlder(file, chronoLocalDate.atTime(localTime)); 1769 } 1770 1771 /** 1772 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate} at the specified 1773 * {@link OffsetTime}. 1774 * 1775 * @param file the {@link File} of which the modification date must be compared 1776 * @param chronoLocalDate the date reference 1777 * @param offsetTime the time reference 1778 * @return true if the {@link File} exists and has been modified after the given {@link ChronoLocalDate} at the given 1779 * {@link OffsetTime}. 1780 * @throws NullPointerException if the file, local date or zone ID is {@code null} 1781 * @since 2.12.0 1782 */ isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime)1783 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) { 1784 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); 1785 Objects.requireNonNull(offsetTime, "offsetTime"); 1786 return isFileOlder(file, chronoLocalDate.atTime(offsetTime.toLocalTime())); 1787 } 1788 1789 /** 1790 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime} 1791 * at the system-default time zone. 1792 * 1793 * <p>Note: The input date and time is assumed to be in the system default time-zone. To use a 1794 * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) 1795 * isFileOlder(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid 1796 * {@link ZoneId}. 1797 * 1798 * @param file the {@link File} of which the modification date must be compared. 1799 * @param chronoLocalDateTime the date reference. 1800 * @return true if the {@link File} exists and has been modified before the given 1801 * {@link ChronoLocalDateTime} at the system-default time zone. 1802 * @throws NullPointerException if the file or local date time is {@code null}. 1803 * @see ZoneId#systemDefault() 1804 * @since 2.8.0 1805 */ isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime)1806 public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) { 1807 return isFileOlder(file, chronoLocalDateTime, ZoneId.systemDefault()); 1808 } 1809 1810 /** 1811 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime} 1812 * at the specified {@link ZoneId}. 1813 * 1814 * @param file the {@link File} of which the modification date must be compared. 1815 * @param chronoLocalDateTime the date reference. 1816 * @param zoneId the time zone. 1817 * @return true if the {@link File} exists and has been modified before the given 1818 * {@link ChronoLocalDateTime} at the given {@link ZoneId}. 1819 * @throws NullPointerException if the file, local date time or zone ID is {@code null}. 1820 * @since 2.8.0 1821 */ isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId)1822 public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) { 1823 Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); 1824 Objects.requireNonNull(zoneId, "zoneId"); 1825 return isFileOlder(file, chronoLocalDateTime.atZone(zoneId)); 1826 } 1827 1828 /** 1829 * Tests if the specified {@link File} is older than the specified {@link ChronoZonedDateTime}. 1830 * 1831 * @param file the {@link File} of which the modification date must be compared. 1832 * @param chronoZonedDateTime the date reference. 1833 * @return true if the {@link File} exists and has been modified before the given 1834 * {@link ChronoZonedDateTime}. 1835 * @throws NullPointerException if the file or zoned date time is {@code null}. 1836 * @since 2.8.0 1837 */ isFileOlder(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime)1838 public static boolean isFileOlder(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) { 1839 Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); 1840 return isFileOlder(file, chronoZonedDateTime.toInstant()); 1841 } 1842 1843 /** 1844 * Tests if the specified {@link File} is older than the specified {@link Date}. 1845 * 1846 * @param file the {@link File} of which the modification date must be compared. 1847 * @param date the date reference. 1848 * @return true if the {@link File} exists and has been modified before the given {@link Date}. 1849 * @throws NullPointerException if the file or date is {@code null}. 1850 */ isFileOlder(final File file, final Date date)1851 public static boolean isFileOlder(final File file, final Date date) { 1852 Objects.requireNonNull(date, "date"); 1853 return isFileOlder(file, date.getTime()); 1854 } 1855 1856 /** 1857 * Tests if the specified {@link File} is older than the reference {@link File}. 1858 * 1859 * @param file the {@link File} of which the modification date must be compared. 1860 * @param reference the {@link File} of which the modification date is used. 1861 * @return true if the {@link File} exists and has been modified before the reference {@link File}. 1862 * @throws NullPointerException if the file or reference file is {@code null}. 1863 * @throws IllegalArgumentException if the reference file doesn't exist. 1864 */ isFileOlder(final File file, final File reference)1865 public static boolean isFileOlder(final File file, final File reference) { 1866 requireExists(reference, "reference"); 1867 return Uncheck.get(() -> PathUtils.isOlder(file.toPath(), reference.toPath())); 1868 } 1869 1870 /** 1871 * Tests if the specified {@link File} is older than the specified {@link FileTime}. 1872 * 1873 * @param file the {@link File} of which the modification date must be compared. 1874 * @param fileTime the file time reference. 1875 * @return true if the {@link File} exists and has been modified before the given {@link FileTime}. 1876 * @throws IOException if an I/O error occurs. 1877 * @throws NullPointerException if the file or local date is {@code null}. 1878 * @since 2.12.0 1879 */ isFileOlder(final File file, final FileTime fileTime)1880 public static boolean isFileOlder(final File file, final FileTime fileTime) throws IOException { 1881 Objects.requireNonNull(file, "file"); 1882 return PathUtils.isOlder(file.toPath(), fileTime); 1883 } 1884 1885 /** 1886 * Tests if the specified {@link File} is older than the specified {@link Instant}. 1887 * 1888 * @param file the {@link File} of which the modification date must be compared. 1889 * @param instant the date reference. 1890 * @return true if the {@link File} exists and has been modified before the given {@link Instant}. 1891 * @throws NullPointerException if the file or instant is {@code null}. 1892 * @since 2.8.0 1893 */ isFileOlder(final File file, final Instant instant)1894 public static boolean isFileOlder(final File file, final Instant instant) { 1895 Objects.requireNonNull(instant, "instant"); 1896 return Uncheck.get(() -> PathUtils.isOlder(file.toPath(), instant)); 1897 } 1898 1899 /** 1900 * Tests if the specified {@link File} is older than the specified time reference. 1901 * 1902 * @param file the {@link File} of which the modification date must be compared. 1903 * @param timeMillis the time reference measured in milliseconds since the 1904 * epoch (00:00:00 GMT, January 1, 1970). 1905 * @return true if the {@link File} exists and has been modified before the given time reference. 1906 * @throws NullPointerException if the file is {@code null}. 1907 */ isFileOlder(final File file, final long timeMillis)1908 public static boolean isFileOlder(final File file, final long timeMillis) { 1909 Objects.requireNonNull(file, "file"); 1910 return Uncheck.get(() -> PathUtils.isOlder(file.toPath(), timeMillis)); 1911 } 1912 1913 /** 1914 * Tests if the specified {@link File} is older than the specified {@link OffsetDateTime}. 1915 * 1916 * @param file the {@link File} of which the modification date must be compared 1917 * @param offsetDateTime the date reference 1918 * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}. 1919 * @throws NullPointerException if the file or zoned date time is {@code null} 1920 * @since 2.12.0 1921 */ isFileOlder(final File file, final OffsetDateTime offsetDateTime)1922 public static boolean isFileOlder(final File file, final OffsetDateTime offsetDateTime) { 1923 Objects.requireNonNull(offsetDateTime, "offsetDateTime"); 1924 return isFileOlder(file, offsetDateTime.toInstant()); 1925 } 1926 1927 /** 1928 * Tests whether the specified {@link File} is a regular file or not. Implemented as a 1929 * null-safe delegate to {@link Files#isRegularFile(Path path, LinkOption... options)}. 1930 * 1931 * @param file the path to the file. 1932 * @param options options indicating how symbolic links are handled 1933 * @return {@code true} if the file is a regular file; {@code false} if 1934 * the path is null, the file does not exist, is not a regular file, or it cannot 1935 * be determined if the file is a regular file or not. 1936 * @throws SecurityException In the case of the default provider, and a security manager is installed, the 1937 * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read 1938 * access to the directory. 1939 * @since 2.9.0 1940 */ isRegularFile(final File file, final LinkOption... options)1941 public static boolean isRegularFile(final File file, final LinkOption... options) { 1942 return file != null && Files.isRegularFile(file.toPath(), options); 1943 } 1944 1945 /** 1946 * Tests whether the specified file is a symbolic link rather than an actual file. 1947 * <p> 1948 * This method delegates to {@link Files#isSymbolicLink(Path path)} 1949 * </p> 1950 * 1951 * @param file the file to test. 1952 * @return true if the file is a symbolic link, see {@link Files#isSymbolicLink(Path path)}. 1953 * @since 2.0 1954 * @see Files#isSymbolicLink(Path) 1955 */ isSymlink(final File file)1956 public static boolean isSymlink(final File file) { 1957 return file != null && Files.isSymbolicLink(file.toPath()); 1958 } 1959 1960 /** 1961 * Iterates over the files in given directory (and optionally 1962 * its subdirectories). 1963 * <p> 1964 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. 1965 * </p> 1966 * <p> 1967 * All files found are filtered by an IOFileFilter. 1968 * </p> 1969 * 1970 * @param directory the directory to search in 1971 * @param fileFilter filter to apply when finding files. 1972 * @param dirFilter optional filter to apply when finding subdirectories. 1973 * If this parameter is {@code null}, subdirectories will not be included in the 1974 * search. Use TrueFileFilter.INSTANCE to match all directories. 1975 * @return an iterator of {@link File} for the matching files 1976 * @see org.apache.commons.io.filefilter.FileFilterUtils 1977 * @see org.apache.commons.io.filefilter.NameFileFilter 1978 * @since 1.2 1979 */ iterateFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter)1980 public static Iterator<File> iterateFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 1981 return listFiles(directory, fileFilter, dirFilter).iterator(); 1982 } 1983 1984 /** 1985 * Iterates over the files in a given directory (and optionally 1986 * its subdirectories) which match an array of extensions. 1987 * <p> 1988 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. 1989 * </p> 1990 * 1991 * @param directory the directory to search in 1992 * @param extensions an array of extensions, for example, {"java","xml"}. If this 1993 * parameter is {@code null}, all files are returned. 1994 * @param recursive if true all subdirectories are searched as well 1995 * @return an iterator of {@link File} with the matching files 1996 * @since 1.2 1997 */ iterateFiles(final File directory, final String[] extensions, final boolean recursive)1998 public static Iterator<File> iterateFiles(final File directory, final String[] extensions, final boolean recursive) { 1999 return StreamIterator.iterator(Uncheck.get(() -> streamFiles(directory, recursive, extensions))); 2000 } 2001 2002 /** 2003 * Iterates over the files in given directory (and optionally 2004 * its subdirectories). 2005 * <p> 2006 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. 2007 * </p> 2008 * <p> 2009 * All files found are filtered by an IOFileFilter. 2010 * </p> 2011 * <p> 2012 * The resulting iterator includes the subdirectories themselves. 2013 * </p> 2014 * 2015 * @param directory the directory to search in 2016 * @param fileFilter filter to apply when finding files. 2017 * @param dirFilter optional filter to apply when finding subdirectories. 2018 * If this parameter is {@code null}, subdirectories will not be included in the 2019 * search. Use TrueFileFilter.INSTANCE to match all directories. 2020 * @return an iterator of {@link File} for the matching files 2021 * @see org.apache.commons.io.filefilter.FileFilterUtils 2022 * @see org.apache.commons.io.filefilter.NameFileFilter 2023 * @since 2.2 2024 */ iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter)2025 public static Iterator<File> iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 2026 return listFilesAndDirs(directory, fileFilter, dirFilter).iterator(); 2027 } 2028 2029 /** 2030 * Returns the last modification time in milliseconds via 2031 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. 2032 * <p> 2033 * For the best precision, use {@link #lastModifiedFileTime(File)}. 2034 * </p> 2035 * <p> 2036 * Use this method to avoid issues with {@link File#lastModified()} like 2037 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is 2038 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10. 2039 * </p> 2040 * 2041 * @param file The File to query. 2042 * @return See {@link java.nio.file.attribute.FileTime#toMillis()}. 2043 * @throws IOException if an I/O error occurs. 2044 * @since 2.9.0 2045 */ lastModified(final File file)2046 public static long lastModified(final File file) throws IOException { 2047 // https://bugs.openjdk.java.net/browse/JDK-8177809 2048 // File.lastModified() is losing milliseconds (always ends in 000) 2049 // This bug is in OpenJDK 8 and 9, and fixed in 10. 2050 return lastModifiedFileTime(file).toMillis(); 2051 } 2052 2053 /** 2054 * Returns the last modification {@link FileTime} via 2055 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. 2056 * <p> 2057 * Use this method to avoid issues with {@link File#lastModified()} like 2058 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is 2059 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10. 2060 * </p> 2061 * 2062 * @param file The File to query. 2063 * @return See {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. 2064 * @throws IOException if an I/O error occurs. 2065 * @since 2.12.0 2066 */ lastModifiedFileTime(final File file)2067 public static FileTime lastModifiedFileTime(final File file) throws IOException { 2068 // https://bugs.openjdk.java.net/browse/JDK-8177809 2069 // File.lastModified() is losing milliseconds (always ends in 000) 2070 // This bug is in OpenJDK 8 and 9, and fixed in 10. 2071 return Files.getLastModifiedTime(Objects.requireNonNull(file.toPath(), "file")); 2072 } 2073 2074 /** 2075 * Returns the last modification time in milliseconds via 2076 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}. 2077 * <p> 2078 * For the best precision, use {@link #lastModifiedFileTime(File)}. 2079 * </p> 2080 * <p> 2081 * Use this method to avoid issues with {@link File#lastModified()} like 2082 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is 2083 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10. 2084 * </p> 2085 * 2086 * @param file The File to query. 2087 * @return See {@link java.nio.file.attribute.FileTime#toMillis()}. 2088 * @throws UncheckedIOException if an I/O error occurs. 2089 * @since 2.9.0 2090 */ lastModifiedUnchecked(final File file)2091 public static long lastModifiedUnchecked(final File file) { 2092 // https://bugs.openjdk.java.net/browse/JDK-8177809 2093 // File.lastModified() is losing milliseconds (always ends in 000) 2094 // This bug is in OpenJDK 8 and 9, and fixed in 10. 2095 return Uncheck.apply(FileUtils::lastModified, file); 2096 } 2097 2098 /** 2099 * Returns an Iterator for the lines in a {@link File} using the default encoding for the VM. 2100 * 2101 * @param file the file to open for input, must not be {@code null} 2102 * @return an Iterator of the lines in the file, never {@code null} 2103 * @throws NullPointerException if file is {@code null}. 2104 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some 2105 * other reason cannot be opened for reading. 2106 * @throws IOException if an I/O error occurs. 2107 * @see #lineIterator(File, String) 2108 * @since 1.3 2109 */ lineIterator(final File file)2110 public static LineIterator lineIterator(final File file) throws IOException { 2111 return lineIterator(file, null); 2112 } 2113 2114 /** 2115 * Returns an Iterator for the lines in a {@link File}. 2116 * <p> 2117 * This method opens an {@link InputStream} for the file. 2118 * When you have finished with the iterator you should close the stream 2119 * to free internal resources. This can be done by using a try-with-resources block or calling the 2120 * {@link LineIterator#close()} method. 2121 * </p> 2122 * <p> 2123 * The recommended usage pattern is: 2124 * </p> 2125 * <pre> 2126 * LineIterator it = FileUtils.lineIterator(file, StandardCharsets.UTF_8.name()); 2127 * try { 2128 * while (it.hasNext()) { 2129 * String line = it.nextLine(); 2130 * /// do something with line 2131 * } 2132 * } finally { 2133 * LineIterator.closeQuietly(iterator); 2134 * } 2135 * </pre> 2136 * <p> 2137 * If an exception occurs during the creation of the iterator, the 2138 * underlying stream is closed. 2139 * </p> 2140 * 2141 * @param file the file to open for input, must not be {@code null} 2142 * @param charsetName the name of the requested charset, {@code null} means platform default 2143 * @return a LineIterator for lines in the file, never {@code null}; MUST be closed by the caller. 2144 * @throws NullPointerException if file is {@code null}. 2145 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some 2146 * other reason cannot be opened for reading. 2147 * @throws IOException if an I/O error occurs. 2148 * @since 1.2 2149 */ 2150 @SuppressWarnings("resource") // Caller closes the result LineIterator. lineIterator(final File file, final String charsetName)2151 public static LineIterator lineIterator(final File file, final String charsetName) throws IOException { 2152 InputStream inputStream = null; 2153 try { 2154 inputStream = Files.newInputStream(file.toPath()); 2155 return IOUtils.lineIterator(inputStream, charsetName); 2156 } catch (final IOException | RuntimeException ex) { 2157 IOUtils.closeQuietly(inputStream, ex::addSuppressed); 2158 throw ex; 2159 } 2160 } 2161 listAccumulate(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter, final FileVisitOption... options)2162 private static AccumulatorPathVisitor listAccumulate(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter, 2163 final FileVisitOption... options) throws IOException { 2164 final boolean isDirFilterSet = dirFilter != null; 2165 final FileEqualsFileFilter rootDirFilter = new FileEqualsFileFilter(directory); 2166 final PathFilter dirPathFilter = isDirFilterSet ? rootDirFilter.or(dirFilter) : rootDirFilter; 2167 final AccumulatorPathVisitor visitor = new AccumulatorPathVisitor(Counters.noopPathCounters(), fileFilter, dirPathFilter, 2168 (p, e) -> FileVisitResult.CONTINUE); 2169 final Set<FileVisitOption> optionSet = new HashSet<>(); 2170 Collections.addAll(optionSet, options); 2171 Files.walkFileTree(directory.toPath(), optionSet, toMaxDepth(isDirFilterSet), visitor); 2172 return visitor; 2173 } 2174 2175 /** 2176 * Lists files in a directory, asserting that the supplied directory exists and is a directory. 2177 * 2178 * @param directory The directory to list 2179 * @param fileFilter Optional file filter, may be null. 2180 * @return The files in the directory, never {@code null}. 2181 * @throws NullPointerException if directory is {@code null}. 2182 * @throws IllegalArgumentException if directory does not exist or is not a directory. 2183 * @throws IOException if an I/O error occurs. 2184 */ listFiles(final File directory, final FileFilter fileFilter)2185 private static File[] listFiles(final File directory, final FileFilter fileFilter) throws IOException { 2186 requireDirectoryExists(directory, "directory"); 2187 final File[] files = fileFilter == null ? directory.listFiles() : directory.listFiles(fileFilter); 2188 if (files == null) { 2189 // null if the directory does not denote a directory, or if an I/O error occurs. 2190 throw new IOException("Unknown I/O error listing contents of directory: " + directory); 2191 } 2192 return files; 2193 } 2194 2195 /** 2196 * Finds files within a given directory (and optionally its 2197 * subdirectories). All files found are filtered by an IOFileFilter. 2198 * <p> 2199 * If your search should recurse into subdirectories you can pass in 2200 * an IOFileFilter for directories. You don't need to bind a 2201 * DirectoryFileFilter (via logical AND) to this filter. This method does 2202 * that for you. 2203 * </p> 2204 * <p> 2205 * An example: If you want to search through all directories called 2206 * "temp" you pass in {@code FileFilterUtils.NameFileFilter("temp")} 2207 * </p> 2208 * <p> 2209 * Another common usage of this method is find files in a directory 2210 * tree but ignoring the directories generated CVS. You can simply pass 2211 * in {@code FileFilterUtils.makeCVSAware(null)}. 2212 * </p> 2213 * 2214 * @param directory the directory to search in 2215 * @param fileFilter filter to apply when finding files. Must not be {@code null}, 2216 * use {@link TrueFileFilter#INSTANCE} to match all files in selected directories. 2217 * @param dirFilter optional filter to apply when finding subdirectories. 2218 * If this parameter is {@code null}, subdirectories will not be included in the 2219 * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. 2220 * @return a collection of {@link File} with the matching files 2221 * @see org.apache.commons.io.filefilter.FileFilterUtils 2222 * @see org.apache.commons.io.filefilter.NameFileFilter 2223 */ listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter)2224 public static Collection<File> listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 2225 final AccumulatorPathVisitor visitor = Uncheck 2226 .apply(d -> listAccumulate(d, FileFileFilter.INSTANCE.and(fileFilter), dirFilter, FileVisitOption.FOLLOW_LINKS), directory); 2227 return toList(visitor.getFileList().stream().map(Path::toFile)); 2228 } 2229 2230 /** 2231 * Lists files within a given directory (and optionally its subdirectories) 2232 * which match an array of extensions. 2233 * 2234 * @param directory the directory to search in 2235 * @param extensions an array of extensions, for example, {"java","xml"}. If this 2236 * parameter is {@code null}, all files are returned. 2237 * @param recursive if true all subdirectories are searched as well 2238 * @return a collection of {@link File} with the matching files 2239 */ listFiles(final File directory, final String[] extensions, final boolean recursive)2240 public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) { 2241 try (Stream<File> fileStream = Uncheck.get(() -> streamFiles(directory, recursive, extensions))) { 2242 return toList(fileStream); 2243 } 2244 } 2245 2246 /** 2247 * Finds files within a given directory (and optionally its 2248 * subdirectories). All files found are filtered by an IOFileFilter. 2249 * <p> 2250 * The resulting collection includes the starting directory and 2251 * any subdirectories that match the directory filter. 2252 * </p> 2253 * 2254 * @param directory the directory to search in 2255 * @param fileFilter filter to apply when finding files. 2256 * @param dirFilter optional filter to apply when finding subdirectories. 2257 * If this parameter is {@code null}, subdirectories will not be included in the 2258 * search. Use TrueFileFilter.INSTANCE to match all directories. 2259 * @return a collection of {@link File} with the matching files 2260 * @see org.apache.commons.io.FileUtils#listFiles 2261 * @see org.apache.commons.io.filefilter.FileFilterUtils 2262 * @see org.apache.commons.io.filefilter.NameFileFilter 2263 * @since 2.2 2264 */ listFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter)2265 public static Collection<File> listFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 2266 final AccumulatorPathVisitor visitor = Uncheck.apply(d -> listAccumulate(d, fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS), 2267 directory); 2268 final List<Path> list = visitor.getFileList(); 2269 list.addAll(visitor.getDirList()); 2270 return toList(list.stream().map(Path::toFile)); 2271 } 2272 2273 /** 2274 * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure. 2275 * <p> 2276 * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is 2277 * null, nothing happens. 2278 * </p> 2279 * 2280 * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens. 2281 * @return the given directory. 2282 * @throws IOException if the directory was not created along with all its parent directories. 2283 * @throws IOException if the given file object is not a directory. 2284 * @throws SecurityException See {@link File#mkdirs()}. 2285 * @see File#mkdirs() 2286 */ mkdirs(final File directory)2287 private static File mkdirs(final File directory) throws IOException { 2288 if (directory != null && !directory.mkdirs() && !directory.isDirectory()) { 2289 throw new IOException("Cannot create directory '" + directory + "'."); 2290 } 2291 return directory; 2292 } 2293 2294 /** 2295 * Moves a directory. 2296 * <p> 2297 * When the destination directory is on another file system, do a "copy and delete". 2298 * </p> 2299 * 2300 * @param srcDir the directory to be moved. 2301 * @param destDir the destination directory. 2302 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2303 * @throws IllegalArgumentException if the source or destination is invalid. 2304 * @throws FileNotFoundException if the source does not exist. 2305 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2306 * @since 1.4 2307 */ moveDirectory(final File srcDir, final File destDir)2308 public static void moveDirectory(final File srcDir, final File destDir) throws IOException { 2309 validateMoveParameters(srcDir, destDir); 2310 requireDirectory(srcDir, "srcDir"); 2311 requireAbsent(destDir, "destDir"); 2312 if (!srcDir.renameTo(destDir)) { 2313 if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) { 2314 throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir); 2315 } 2316 copyDirectory(srcDir, destDir); 2317 deleteDirectory(srcDir); 2318 if (srcDir.exists()) { 2319 throw new IOException("Failed to delete original directory '" + srcDir + 2320 "' after copy to '" + destDir + "'"); 2321 } 2322 } 2323 } 2324 2325 /** 2326 * Moves a directory to another directory. 2327 * <p> 2328 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2329 * </p> 2330 * 2331 * @param source the file to be moved. 2332 * @param destDir the destination file. 2333 * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an 2334 * IOException. 2335 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2336 * @throws IllegalArgumentException if the source or destination is invalid. 2337 * @throws FileNotFoundException if the source does not exist. 2338 * @throws IOException if the directory was not created along with all its parent directories, if enabled. 2339 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2340 * @throws SecurityException See {@link File#mkdirs()}. 2341 * @since 1.4 2342 */ moveDirectoryToDirectory(final File source, final File destDir, final boolean createDestDir)2343 public static void moveDirectoryToDirectory(final File source, final File destDir, final boolean createDestDir) throws IOException { 2344 validateMoveParameters(source, destDir); 2345 if (!destDir.isDirectory()) { 2346 if (destDir.exists()) { 2347 throw new IOException("Destination '" + destDir + "' is not a directory"); 2348 } 2349 if (!createDestDir) { 2350 throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + false + "]"); 2351 } 2352 mkdirs(destDir); 2353 } 2354 moveDirectory(source, new File(destDir, source.getName())); 2355 } 2356 2357 /** 2358 * Moves a file preserving attributes. 2359 * <p> 2360 * Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}. 2361 * </p> 2362 * <p> 2363 * When the destination file is on another file system, do a "copy and delete". 2364 * </p> 2365 * 2366 * @param srcFile the file to be moved. 2367 * @param destFile the destination file. 2368 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2369 * @throws FileExistsException if the destination file exists. 2370 * @throws FileNotFoundException if the source file does not exist. 2371 * @throws IOException if source or destination is invalid. 2372 * @throws IOException if an error occurs. 2373 * @since 1.4 2374 */ moveFile(final File srcFile, final File destFile)2375 public static void moveFile(final File srcFile, final File destFile) throws IOException { 2376 moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES); 2377 } 2378 2379 /** 2380 * Moves a file. 2381 * <p> 2382 * When the destination file is on another file system, do a "copy and delete". 2383 * </p> 2384 * 2385 * @param srcFile the file to be moved. 2386 * @param destFile the destination file. 2387 * @param copyOptions Copy options. 2388 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2389 * @throws FileExistsException if the destination file exists. 2390 * @throws FileNotFoundException if the source file does not exist. 2391 * @throws IOException if source or destination is invalid. 2392 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2393 * @since 2.9.0 2394 */ moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions)2395 public static void moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException { 2396 validateMoveParameters(srcFile, destFile); 2397 requireFile(srcFile, "srcFile"); 2398 requireAbsent(destFile, "destFile"); 2399 final boolean rename = srcFile.renameTo(destFile); 2400 if (!rename) { 2401 // Don't interfere with file date on move, handled by StandardCopyOption.COPY_ATTRIBUTES 2402 copyFile(srcFile, destFile, false, copyOptions); 2403 if (!srcFile.delete()) { 2404 FileUtils.deleteQuietly(destFile); 2405 throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'"); 2406 } 2407 } 2408 } 2409 2410 /** 2411 * Moves a file to a directory. 2412 * <p> 2413 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2414 * </p> 2415 * 2416 * @param srcFile the file to be moved. 2417 * @param destDir the destination file. 2418 * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an 2419 * IOException. 2420 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2421 * @throws FileExistsException if the destination file exists. 2422 * @throws FileNotFoundException if the source file does not exist. 2423 * @throws IOException if source or destination is invalid. 2424 * @throws IOException if the directory was not created along with all its parent directories, if enabled. 2425 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2426 * @throws SecurityException See {@link File#mkdirs()}. 2427 * @since 1.4 2428 */ moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir)2429 public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException { 2430 validateMoveParameters(srcFile, destDir); 2431 if (!destDir.exists() && createDestDir) { 2432 mkdirs(destDir); 2433 } 2434 requireExistsChecked(destDir, "destDir"); 2435 requireDirectory(destDir, "destDir"); 2436 moveFile(srcFile, new File(destDir, srcFile.getName())); 2437 } 2438 2439 /** 2440 * Moves a file or directory to a destination directory. 2441 * <p> 2442 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2443 * </p> 2444 * <p> 2445 * When the destination is on another file system, do a "copy and delete". 2446 * </p> 2447 * 2448 * @param src the file or directory to be moved. 2449 * @param destDir the destination directory. 2450 * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an IOException. 2451 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2452 * @throws FileExistsException if the directory or file exists in the destination directory. 2453 * @throws FileNotFoundException if the source file does not exist. 2454 * @throws IOException if source or destination is invalid. 2455 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2456 * @since 1.4 2457 */ moveToDirectory(final File src, final File destDir, final boolean createDestDir)2458 public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException { 2459 validateMoveParameters(src, destDir); 2460 if (src.isDirectory()) { 2461 moveDirectoryToDirectory(src, destDir, createDestDir); 2462 } else { 2463 moveFileToDirectory(src, destDir, createDestDir); 2464 } 2465 } 2466 2467 /** 2468 * Creates a new OutputStream by opening or creating a file, returning an output stream that may be used to write bytes 2469 * to the file. 2470 * 2471 * @param append Whether or not to append. 2472 * @param file the File. 2473 * @return a new OutputStream. 2474 * @throws IOException if an I/O error occurs. 2475 * @see PathUtils#newOutputStream(Path, boolean) 2476 * @since 2.12.0 2477 */ newOutputStream(final File file, final boolean append)2478 public static OutputStream newOutputStream(final File file, final boolean append) throws IOException { 2479 return PathUtils.newOutputStream(Objects.requireNonNull(file, "file").toPath(), append); 2480 } 2481 2482 /** 2483 * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling 2484 * {@code new FileInputStream(file)}. 2485 * <p> 2486 * At the end of the method either the stream will be successfully opened, or an exception will have been thrown. 2487 * </p> 2488 * <p> 2489 * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a 2490 * directory. An exception is thrown if the file exists but cannot be read. 2491 * </p> 2492 * 2493 * @param file the file to open for input, must not be {@code null} 2494 * @return a new {@link FileInputStream} for the specified file 2495 * @throws NullPointerException if file is {@code null}. 2496 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some 2497 * other reason cannot be opened for reading. 2498 * @throws IOException See FileNotFoundException above, FileNotFoundException is a subclass of IOException. 2499 * @since 1.3 2500 */ openInputStream(final File file)2501 public static FileInputStream openInputStream(final File file) throws IOException { 2502 Objects.requireNonNull(file, "file"); 2503 return new FileInputStream(file); 2504 } 2505 2506 /** 2507 * Opens a {@link FileOutputStream} for the specified file, checking and 2508 * creating the parent directory if it does not exist. 2509 * <p> 2510 * At the end of the method either the stream will be successfully opened, 2511 * or an exception will have been thrown. 2512 * </p> 2513 * <p> 2514 * The parent directory will be created if it does not exist. 2515 * The file will be created if it does not exist. 2516 * An exception is thrown if the file object exists but is a directory. 2517 * An exception is thrown if the file exists but cannot be written to. 2518 * An exception is thrown if the parent directory cannot be created. 2519 * </p> 2520 * 2521 * @param file the file to open for output, must not be {@code null} 2522 * @return a new {@link FileOutputStream} for the specified file 2523 * @throws NullPointerException if the file object is {@code null}. 2524 * @throws IllegalArgumentException if the file object is a directory 2525 * @throws IllegalArgumentException if the file is not writable. 2526 * @throws IOException if the directories could not be created. 2527 * @since 1.3 2528 */ openOutputStream(final File file)2529 public static FileOutputStream openOutputStream(final File file) throws IOException { 2530 return openOutputStream(file, false); 2531 } 2532 2533 /** 2534 * Opens a {@link FileOutputStream} for the specified file, checking and 2535 * creating the parent directory if it does not exist. 2536 * <p> 2537 * At the end of the method either the stream will be successfully opened, 2538 * or an exception will have been thrown. 2539 * </p> 2540 * <p> 2541 * The parent directory will be created if it does not exist. 2542 * The file will be created if it does not exist. 2543 * An exception is thrown if the file object exists but is a directory. 2544 * An exception is thrown if the file exists but cannot be written to. 2545 * An exception is thrown if the parent directory cannot be created. 2546 * </p> 2547 * 2548 * @param file the file to open for output, must not be {@code null} 2549 * @param append if {@code true}, then bytes will be added to the 2550 * end of the file rather than overwriting 2551 * @return a new {@link FileOutputStream} for the specified file 2552 * @throws NullPointerException if the file object is {@code null}. 2553 * @throws IllegalArgumentException if the file object is a directory 2554 * @throws IllegalArgumentException if the file is not writable. 2555 * @throws IOException if the directories could not be created. 2556 * @since 2.1 2557 */ openOutputStream(final File file, final boolean append)2558 public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException { 2559 Objects.requireNonNull(file, "file"); 2560 if (file.exists()) { 2561 requireFile(file, "file"); 2562 requireCanWrite(file, "file"); 2563 } else { 2564 createParentDirectories(file); 2565 } 2566 return new FileOutputStream(file, append); 2567 } 2568 2569 /** 2570 * Reads the contents of a file into a byte array. 2571 * The file is always closed. 2572 * 2573 * @param file the file to read, must not be {@code null} 2574 * @return the file contents, never {@code null} 2575 * @throws NullPointerException if file is {@code null}. 2576 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2577 * regular file, or for some other reason why the file cannot be opened for reading. 2578 * @since 1.1 2579 */ readFileToByteArray(final File file)2580 public static byte[] readFileToByteArray(final File file) throws IOException { 2581 Objects.requireNonNull(file, "file"); 2582 return Files.readAllBytes(file.toPath()); 2583 } 2584 2585 /** 2586 * Reads the contents of a file into a String using the default encoding for the VM. 2587 * The file is always closed. 2588 * 2589 * @param file the file to read, must not be {@code null} 2590 * @return the file contents, never {@code null} 2591 * @throws NullPointerException if file is {@code null}. 2592 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2593 * regular file, or for some other reason why the file cannot be opened for reading. 2594 * @since 1.3.1 2595 * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) 2596 */ 2597 @Deprecated readFileToString(final File file)2598 public static String readFileToString(final File file) throws IOException { 2599 return readFileToString(file, Charset.defaultCharset()); 2600 } 2601 2602 /** 2603 * Reads the contents of a file into a String. 2604 * The file is always closed. 2605 * 2606 * @param file the file to read, must not be {@code null} 2607 * @param charsetName the name of the requested charset, {@code null} means platform default 2608 * @return the file contents, never {@code null} 2609 * @throws NullPointerException if file is {@code null}. 2610 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2611 * regular file, or for some other reason why the file cannot be opened for reading. 2612 * @since 2.3 2613 */ readFileToString(final File file, final Charset charsetName)2614 public static String readFileToString(final File file, final Charset charsetName) throws IOException { 2615 return IOUtils.toString(() -> Files.newInputStream(file.toPath()), Charsets.toCharset(charsetName)); 2616 } 2617 2618 /** 2619 * Reads the contents of a file into a String. The file is always closed. 2620 * 2621 * @param file the file to read, must not be {@code null} 2622 * @param charsetName the name of the requested charset, {@code null} means platform default 2623 * @return the file contents, never {@code null} 2624 * @throws NullPointerException if file is {@code null}. 2625 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2626 * regular file, or for some other reason why the file cannot be opened for reading. 2627 * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io 2628 * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. 2629 * @since 2.3 2630 */ readFileToString(final File file, final String charsetName)2631 public static String readFileToString(final File file, final String charsetName) throws IOException { 2632 return readFileToString(file, Charsets.toCharset(charsetName)); 2633 } 2634 2635 /** 2636 * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. 2637 * The file is always closed. 2638 * 2639 * @param file the file to read, must not be {@code null} 2640 * @return the list of Strings representing each line in the file, never {@code null} 2641 * @throws NullPointerException if file is {@code null}. 2642 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2643 * regular file, or for some other reason why the file cannot be opened for reading. 2644 * @since 1.3 2645 * @deprecated 2.5 use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) 2646 */ 2647 @Deprecated readLines(final File file)2648 public static List<String> readLines(final File file) throws IOException { 2649 return readLines(file, Charset.defaultCharset()); 2650 } 2651 2652 /** 2653 * Reads the contents of a file line by line to a List of Strings. 2654 * The file is always closed. 2655 * 2656 * @param file the file to read, must not be {@code null} 2657 * @param charset the charset to use, {@code null} means platform default 2658 * @return the list of Strings representing each line in the file, never {@code null} 2659 * @throws NullPointerException if file is {@code null}. 2660 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2661 * regular file, or for some other reason why the file cannot be opened for reading. 2662 * @since 2.3 2663 */ readLines(final File file, final Charset charset)2664 public static List<String> readLines(final File file, final Charset charset) throws IOException { 2665 return Files.readAllLines(file.toPath(), charset); 2666 } 2667 2668 /** 2669 * Reads the contents of a file line by line to a List of Strings. The file is always closed. 2670 * 2671 * @param file the file to read, must not be {@code null} 2672 * @param charsetName the name of the requested charset, {@code null} means platform default 2673 * @return the list of Strings representing each line in the file, never {@code null} 2674 * @throws NullPointerException if file is {@code null}. 2675 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2676 * regular file, or for some other reason why the file cannot be opened for reading. 2677 * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io 2678 * .UnsupportedEncodingException} in version 2.2 if the named charset is unavailable. 2679 * @since 1.1 2680 */ readLines(final File file, final String charsetName)2681 public static List<String> readLines(final File file, final String charsetName) throws IOException { 2682 return readLines(file, Charsets.toCharset(charsetName)); 2683 } 2684 2685 requireAbsent(final File file, final String name)2686 private static void requireAbsent(final File file, final String name) throws FileExistsException { 2687 if (file.exists()) { 2688 throw new FileExistsException(String.format("File element in parameter '%s' already exists: '%s'", name, file)); 2689 } 2690 } 2691 2692 /** 2693 * Throws IllegalArgumentException if the given files' canonical representations are equal. 2694 * 2695 * @param file1 The first file to compare. 2696 * @param file2 The second file to compare. 2697 * @throws IOException if an I/O error occurs. 2698 * @throws IllegalArgumentException if the given files' canonical representations are equal. 2699 */ requireCanonicalPathsNotEquals(final File file1, final File file2)2700 private static void requireCanonicalPathsNotEquals(final File file1, final File file2) throws IOException { 2701 final String canonicalPath = file1.getCanonicalPath(); 2702 if (canonicalPath.equals(file2.getCanonicalPath())) { 2703 throw new IllegalArgumentException(String 2704 .format("File canonical paths are equal: '%s' (file1='%s', file2='%s')", canonicalPath, file1, file2)); 2705 } 2706 } 2707 2708 /** 2709 * Throws an {@link IllegalArgumentException} if the file is not writable. This provides a more precise exception 2710 * message than a plain access denied. 2711 * 2712 * @param file The file to test. 2713 * @param name The parameter name to use in the exception message. 2714 * @throws NullPointerException if the given {@link File} is {@code null}. 2715 * @throws IllegalArgumentException if the file is not writable. 2716 */ requireCanWrite(final File file, final String name)2717 private static void requireCanWrite(final File file, final String name) { 2718 Objects.requireNonNull(file, "file"); 2719 if (!file.canWrite()) { 2720 throw new IllegalArgumentException("File parameter '" + name + " is not writable: '" + file + "'"); 2721 } 2722 } 2723 2724 /** 2725 * Requires that the given {@link File} is a directory. 2726 * 2727 * @param directory The {@link File} to check. 2728 * @param name The parameter name to use in the exception message in case of null input or if the file is not a directory. 2729 * @return the given directory. 2730 * @throws NullPointerException if the given {@link File} is {@code null}. 2731 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a directory. 2732 */ requireDirectory(final File directory, final String name)2733 private static File requireDirectory(final File directory, final String name) { 2734 Objects.requireNonNull(directory, name); 2735 if (!directory.isDirectory()) { 2736 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'"); 2737 } 2738 return directory; 2739 } 2740 2741 /** 2742 * Requires that the given {@link File} exists and is a directory. 2743 * 2744 * @param directory The {@link File} to check. 2745 * @param name The parameter name to use in the exception message in case of null input. 2746 * @return the given directory. 2747 * @throws NullPointerException if the given {@link File} is {@code null}. 2748 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a directory. 2749 */ requireDirectoryExists(final File directory, final String name)2750 private static File requireDirectoryExists(final File directory, final String name) { 2751 requireExists(directory, name); 2752 requireDirectory(directory, name); 2753 return directory; 2754 } 2755 2756 /** 2757 * Requires that the given {@link File} is a directory if it exists. 2758 * 2759 * @param directory The {@link File} to check. 2760 * @param name The parameter name to use in the exception message in case of null input. 2761 * @return the given directory. 2762 * @throws NullPointerException if the given {@link File} is {@code null}. 2763 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory. 2764 */ requireDirectoryIfExists(final File directory, final String name)2765 private static File requireDirectoryIfExists(final File directory, final String name) { 2766 Objects.requireNonNull(directory, name); 2767 if (directory.exists()) { 2768 requireDirectory(directory, name); 2769 } 2770 return directory; 2771 } 2772 2773 /** 2774 * Requires that the given {@link File} exists and throws an {@link IllegalArgumentException} if it doesn't. 2775 * 2776 * @param file The {@link File} to check. 2777 * @param fileParamName The parameter name to use in the exception message in case of {@code null} input. 2778 * @return the given file. 2779 * @throws NullPointerException if the given {@link File} is {@code null}. 2780 * @throws IllegalArgumentException if the given {@link File} does not exist. 2781 */ requireExists(final File file, final String fileParamName)2782 private static File requireExists(final File file, final String fileParamName) { 2783 Objects.requireNonNull(file, fileParamName); 2784 if (!file.exists()) { 2785 throw new IllegalArgumentException("File system element for parameter '" + fileParamName + "' does not exist: '" + file + "'"); 2786 } 2787 return file; 2788 } 2789 2790 /** 2791 * Requires that the given {@link File} exists and throws an {@link FileNotFoundException} if it doesn't. 2792 * 2793 * @param file The {@link File} to check. 2794 * @param fileParamName The parameter name to use in the exception message in case of {@code null} input. 2795 * @return the given file. 2796 * @throws NullPointerException if the given {@link File} is {@code null}. 2797 * @throws FileNotFoundException if the given {@link File} does not exist. 2798 */ requireExistsChecked(final File file, final String fileParamName)2799 private static File requireExistsChecked(final File file, final String fileParamName) throws FileNotFoundException { 2800 Objects.requireNonNull(file, fileParamName); 2801 if (!file.exists()) { 2802 throw new FileNotFoundException("File system element for parameter '" + fileParamName + "' does not exist: '" + file + "'"); 2803 } 2804 return file; 2805 } 2806 2807 /** 2808 * Requires that the given {@link File} is a file. 2809 * 2810 * @param file The {@link File} to check. 2811 * @param name The parameter name to use in the exception message. 2812 * @return the given file. 2813 * @throws NullPointerException if the given {@link File} is {@code null}. 2814 * @throws IllegalArgumentException if the given {@link File} does not exist or is not a file. 2815 */ requireFile(final File file, final String name)2816 private static File requireFile(final File file, final String name) { 2817 Objects.requireNonNull(file, name); 2818 if (!file.isFile()) { 2819 throw new IllegalArgumentException("Parameter '" + name + "' is not a file: " + file); 2820 } 2821 return file; 2822 } 2823 2824 /** 2825 * Requires parameter attributes for a file copy operation. 2826 * 2827 * @param source the source file 2828 * @param destination the destination 2829 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2830 * @throws FileNotFoundException if the source does not exist. 2831 */ requireFileCopy(final File source, final File destination)2832 private static void requireFileCopy(final File source, final File destination) throws FileNotFoundException { 2833 requireExistsChecked(source, "source"); 2834 Objects.requireNonNull(destination, "destination"); 2835 } 2836 2837 /** 2838 * Requires that the given {@link File} is a file if it exists. 2839 * 2840 * @param file The {@link File} to check. 2841 * @param name The parameter name to use in the exception message in case of null input. 2842 * @return the given directory. 2843 * @throws NullPointerException if the given {@link File} is {@code null}. 2844 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory. 2845 */ requireFileIfExists(final File file, final String name)2846 private static File requireFileIfExists(final File file, final String name) { 2847 Objects.requireNonNull(file, name); 2848 return file.exists() ? requireFile(file, name) : file; 2849 } 2850 2851 /** 2852 * Set file lastModifiedTime, lastAccessTime and creationTime to match source file 2853 * 2854 * @param sourceFile The source file to query. 2855 * @param targetFile The target file or directory to set. 2856 * @return {@code true} if and only if the operation succeeded; 2857 * {@code false} otherwise 2858 * @throws NullPointerException if sourceFile is {@code null}. 2859 * @throws NullPointerException if targetFile is {@code null}. 2860 */ setTimes(final File sourceFile, final File targetFile)2861 private static boolean setTimes(final File sourceFile, final File targetFile) { 2862 Objects.requireNonNull(sourceFile, "sourceFile"); 2863 Objects.requireNonNull(targetFile, "targetFile"); 2864 try { 2865 // Set creation, modified, last accessed to match source file 2866 final BasicFileAttributes srcAttr = Files.readAttributes(sourceFile.toPath(), BasicFileAttributes.class); 2867 final BasicFileAttributeView destAttrView = Files.getFileAttributeView(targetFile.toPath(), BasicFileAttributeView.class); 2868 // null guards are not needed; BasicFileAttributes.setTimes(...) is null safe 2869 destAttrView.setTimes(srcAttr.lastModifiedTime(), srcAttr.lastAccessTime(), srcAttr.creationTime()); 2870 return true; 2871 } catch (IOException ignored) { 2872 // Fallback: Only set modified time to match source file 2873 return targetFile.setLastModified(sourceFile.lastModified()); 2874 } 2875 2876 // TODO: (Help!) Determine historically why setLastModified(File, File) needed PathUtils.setLastModifiedTime() if 2877 // sourceFile.isFile() was true, but needed setLastModifiedTime(File, long) if sourceFile.isFile() was false 2878 } 2879 2880 /** 2881 * Returns the size of the specified file or directory. If the provided 2882 * {@link File} is a regular file, then the file's length is returned. 2883 * If the argument is a directory, then the size of the directory is 2884 * calculated recursively. If a directory or subdirectory is security 2885 * restricted, its size will not be included. 2886 * <p> 2887 * Note that overflow is not detected, and the return value may be negative if 2888 * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative 2889 * method that does not overflow. 2890 * </p> 2891 * 2892 * @param file the regular file or directory to return the size 2893 * of (must not be {@code null}). 2894 * 2895 * @return the length of the file, or recursive size of the directory, 2896 * provided (in bytes). 2897 * 2898 * @throws NullPointerException if the file is {@code null}. 2899 * @throws IllegalArgumentException if the file does not exist. 2900 * @throws UncheckedIOException if an IO error occurs. 2901 * @since 2.0 2902 */ sizeOf(final File file)2903 public static long sizeOf(final File file) { 2904 requireExists(file, "file"); 2905 return Uncheck.get(() -> PathUtils.sizeOf(file.toPath())); 2906 } 2907 2908 /** 2909 * Returns the size of the specified file or directory. If the provided 2910 * {@link File} is a regular file, then the file's length is returned. 2911 * If the argument is a directory, then the size of the directory is 2912 * calculated recursively. If a directory or subdirectory is security 2913 * restricted, its size will not be included. 2914 * 2915 * @param file the regular file or directory to return the size 2916 * of (must not be {@code null}). 2917 * 2918 * @return the length of the file, or recursive size of the directory, 2919 * provided (in bytes). 2920 * 2921 * @throws NullPointerException if the file is {@code null}. 2922 * @throws IllegalArgumentException if the file does not exist. 2923 * @throws UncheckedIOException if an IO error occurs. 2924 * @since 2.4 2925 */ sizeOfAsBigInteger(final File file)2926 public static BigInteger sizeOfAsBigInteger(final File file) { 2927 requireExists(file, "file"); 2928 return Uncheck.get(() -> PathUtils.sizeOfAsBigInteger(file.toPath())); 2929 } 2930 2931 /** 2932 * Counts the size of a directory recursively (sum of the length of all files). 2933 * <p> 2934 * Note that overflow is not detected, and the return value may be negative if 2935 * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative 2936 * method that does not overflow. 2937 * </p> 2938 * 2939 * @param directory directory to inspect, must not be {@code null}. 2940 * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total 2941 * is greater than {@link Long#MAX_VALUE}. 2942 * @throws NullPointerException if the directory is {@code null}. 2943 * @throws UncheckedIOException if an IO error occurs. 2944 */ sizeOfDirectory(final File directory)2945 public static long sizeOfDirectory(final File directory) { 2946 requireDirectoryExists(directory, "directory"); 2947 return Uncheck.get(() -> PathUtils.sizeOfDirectory(directory.toPath())); 2948 } 2949 2950 /** 2951 * Counts the size of a directory recursively (sum of the length of all files). 2952 * 2953 * @param directory directory to inspect, must not be {@code null}. 2954 * @return size of directory in bytes, 0 if directory is security restricted. 2955 * @throws NullPointerException if the directory is {@code null}. 2956 * @throws UncheckedIOException if an IO error occurs. 2957 * @since 2.4 2958 */ sizeOfDirectoryAsBigInteger(final File directory)2959 public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) { 2960 requireDirectoryExists(directory, "directory"); 2961 return Uncheck.get(() -> PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath())); 2962 } 2963 2964 /** 2965 * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions. 2966 * <p> 2967 * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a 2968 * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a 2969 * closed stream causes a {@link IllegalStateException}. 2970 * </p> 2971 * 2972 * @param directory the directory to search in 2973 * @param recursive if true all subdirectories are searched as well 2974 * @param extensions an array of extensions, for example, {"java","xml"}. If this parameter is {@code null}, all files are returned. 2975 * @return a Stream of {@link File} for matching files. 2976 * @throws IOException if an I/O error is thrown when accessing the starting file. 2977 * @since 2.9.0 2978 */ streamFiles(final File directory, final boolean recursive, final String... extensions)2979 public static Stream<File> streamFiles(final File directory, final boolean recursive, final String... extensions) throws IOException { 2980 // @formatter:off 2981 final IOFileFilter filter = extensions == null 2982 ? FileFileFilter.INSTANCE 2983 : FileFileFilter.INSTANCE.and(new SuffixFileFilter(toSuffixes(extensions))); 2984 // @formatter:on 2985 return PathUtils.walk(directory.toPath(), filter, toMaxDepth(recursive), false, FileVisitOption.FOLLOW_LINKS).map(Path::toFile); 2986 } 2987 2988 /** 2989 * Converts from a {@link URL} to a {@link File}. 2990 * <p> 2991 * From version 1.1 this method will decode the URL. 2992 * Syntax such as {@code file:///my%20docs/file.txt} will be 2993 * correctly decoded to {@code /my docs/file.txt}. Starting with version 2994 * 1.5, this method uses UTF-8 to decode percent-encoded octets to characters. 2995 * Additionally, malformed percent-encoded octets are handled leniently by 2996 * passing them through literally. 2997 * </p> 2998 * 2999 * @param url the file URL to convert, {@code null} returns {@code null} 3000 * @return the equivalent {@link File} object, or {@code null} 3001 * if the URL's protocol is not {@code file} 3002 */ toFile(final URL url)3003 public static File toFile(final URL url) { 3004 if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { 3005 return null; 3006 } 3007 final String fileName = url.getFile().replace('/', File.separatorChar); 3008 return new File(decodeUrl(fileName)); 3009 } 3010 3011 /** 3012 * Converts each of an array of {@link URL} to a {@link File}. 3013 * <p> 3014 * Returns an array of the same size as the input. 3015 * If the input is {@code null}, an empty array is returned. 3016 * If the input contains {@code null}, the output array contains {@code null} at the same 3017 * index. 3018 * </p> 3019 * <p> 3020 * This method will decode the URL. 3021 * Syntax such as {@code file:///my%20docs/file.txt} will be 3022 * correctly decoded to {@code /my docs/file.txt}. 3023 * </p> 3024 * 3025 * @param urls the file URLs to convert, {@code null} returns empty array 3026 * @return a non-{@code null} array of Files matching the input, with a {@code null} item 3027 * if there was a {@code null} at that index in the input array 3028 * @throws IllegalArgumentException if any file is not a URL file 3029 * @throws IllegalArgumentException if any file is incorrectly encoded 3030 * @since 1.1 3031 */ toFiles(final URL... urls)3032 public static File[] toFiles(final URL... urls) { 3033 if (IOUtils.length(urls) == 0) { 3034 return EMPTY_FILE_ARRAY; 3035 } 3036 final File[] files = new File[urls.length]; 3037 for (int i = 0; i < urls.length; i++) { 3038 final URL url = urls[i]; 3039 if (url != null) { 3040 if (!"file".equalsIgnoreCase(url.getProtocol())) { 3041 throw new IllegalArgumentException("Can only convert file URL to a File: " + url); 3042 } 3043 files[i] = toFile(url); 3044 } 3045 } 3046 return files; 3047 } 3048 3049 /** 3050 * Consumes all of the given stream. 3051 * <p> 3052 * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}. 3053 * </p> 3054 * 3055 * @param stream The stream to consume. 3056 * @return a new List. 3057 */ toList(final Stream<File> stream)3058 private static List<File> toList(final Stream<File> stream) { 3059 return stream.collect(Collectors.toList()); 3060 } 3061 3062 /** 3063 * Converts whether or not to recurse into a recursion max depth. 3064 * 3065 * @param recursive whether or not to recurse 3066 * @return the recursion depth 3067 */ toMaxDepth(final boolean recursive)3068 private static int toMaxDepth(final boolean recursive) { 3069 return recursive ? Integer.MAX_VALUE : 1; 3070 } 3071 3072 /** 3073 * Converts an array of file extensions to suffixes. 3074 * 3075 * @param extensions an array of extensions. Format: {"java", "xml"} 3076 * @return an array of suffixes. Format: {".java", ".xml"} 3077 * @throws NullPointerException if the parameter is null 3078 */ toSuffixes(final String... extensions)3079 private static String[] toSuffixes(final String... extensions) { 3080 return Stream.of(Objects.requireNonNull(extensions, "extensions")).map(e -> "." + e).toArray(String[]::new); 3081 } 3082 3083 /** 3084 * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just 3085 * updates the file's modified time. 3086 * <p> 3087 * NOTE: As from v1.3, this method throws an IOException if the last modified date of the file cannot be set. Also, as 3088 * from v1.3 this method creates parent directories if they do not exist. 3089 * </p> 3090 * 3091 * @param file the File to touch. 3092 * @throws NullPointerException if the parameter is {@code null}. 3093 * @throws IOException if setting the last-modified time failed or an I/O problem occurs. 3094 */ touch(final File file)3095 public static void touch(final File file) throws IOException { 3096 PathUtils.touch(Objects.requireNonNull(file, "file").toPath()); 3097 } 3098 3099 /** 3100 * Converts each of an array of {@link File} to a {@link URL}. 3101 * <p> 3102 * Returns an array of the same size as the input. 3103 * </p> 3104 * 3105 * @param files the files to convert, must not be {@code null} 3106 * @return an array of URLs matching the input 3107 * @throws IOException if a file cannot be converted 3108 * @throws NullPointerException if the parameter is null 3109 */ toURLs(final File... files)3110 public static URL[] toURLs(final File... files) throws IOException { 3111 Objects.requireNonNull(files, "files"); 3112 final URL[] urls = new URL[files.length]; 3113 for (int i = 0; i < urls.length; i++) { 3114 urls[i] = files[i].toURI().toURL(); 3115 } 3116 return urls; 3117 } 3118 3119 /** 3120 * Validates the given arguments. 3121 * <ul> 3122 * <li>Throws {@link NullPointerException} if {@code source} is null</li> 3123 * <li>Throws {@link NullPointerException} if {@code destination} is null</li> 3124 * <li>Throws {@link FileNotFoundException} if {@code source} does not exist</li> 3125 * </ul> 3126 * 3127 * @param source the file or directory to be moved. 3128 * @param destination the destination file or directory. 3129 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 3130 * @throws FileNotFoundException if the source file does not exist. 3131 */ validateMoveParameters(final File source, final File destination)3132 private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException { 3133 Objects.requireNonNull(source, "source"); 3134 Objects.requireNonNull(destination, "destination"); 3135 if (!source.exists()) { 3136 throw new FileNotFoundException("Source '" + source + "' does not exist"); 3137 } 3138 } 3139 3140 /** 3141 * Waits for the file system to propagate a file creation, with a timeout. 3142 * <p> 3143 * This method repeatedly tests {@link Files#exists(Path, LinkOption...)} until it returns 3144 * true up to the maximum time specified in seconds. 3145 * </p> 3146 * 3147 * @param file the file to check, must not be {@code null} 3148 * @param seconds the maximum time in seconds to wait 3149 * @return true if file exists 3150 * @throws NullPointerException if the file is {@code null} 3151 */ waitFor(final File file, final int seconds)3152 public static boolean waitFor(final File file, final int seconds) { 3153 Objects.requireNonNull(file, "file"); 3154 return PathUtils.waitFor(file.toPath(), Duration.ofSeconds(seconds), PathUtils.EMPTY_LINK_OPTION_ARRAY); 3155 } 3156 3157 /** 3158 * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. 3159 * 3160 * @param file the file to write 3161 * @param data the content to write to the file 3162 * @throws IOException in case of an I/O error 3163 * @since 2.0 3164 * @deprecated 2.5 use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding) 3165 */ 3166 @Deprecated write(final File file, final CharSequence data)3167 public static void write(final File file, final CharSequence data) throws IOException { 3168 write(file, data, Charset.defaultCharset(), false); 3169 } 3170 3171 /** 3172 * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. 3173 * 3174 * @param file the file to write 3175 * @param data the content to write to the file 3176 * @param append if {@code true}, then the data will be added to the 3177 * end of the file rather than overwriting 3178 * @throws IOException in case of an I/O error 3179 * @since 2.1 3180 * @deprecated 2.5 use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding) 3181 */ 3182 @Deprecated write(final File file, final CharSequence data, final boolean append)3183 public static void write(final File file, final CharSequence data, final boolean append) throws IOException { 3184 write(file, data, Charset.defaultCharset(), append); 3185 } 3186 3187 /** 3188 * Writes a CharSequence to a file creating the file if it does not exist. 3189 * 3190 * @param file the file to write 3191 * @param data the content to write to the file 3192 * @param charset the name of the requested charset, {@code null} means platform default 3193 * @throws IOException in case of an I/O error 3194 * @since 2.3 3195 */ write(final File file, final CharSequence data, final Charset charset)3196 public static void write(final File file, final CharSequence data, final Charset charset) throws IOException { 3197 write(file, data, charset, false); 3198 } 3199 3200 /** 3201 * Writes a CharSequence to a file creating the file if it does not exist. 3202 * 3203 * @param file the file to write 3204 * @param data the content to write to the file 3205 * @param charset the charset to use, {@code null} means platform default 3206 * @param append if {@code true}, then the data will be added to the 3207 * end of the file rather than overwriting 3208 * @throws IOException in case of an I/O error 3209 * @since 2.3 3210 */ write(final File file, final CharSequence data, final Charset charset, final boolean append)3211 public static void write(final File file, final CharSequence data, final Charset charset, final boolean append) throws IOException { 3212 writeStringToFile(file, Objects.toString(data, null), charset, append); 3213 } 3214 3215 /** 3216 * Writes a CharSequence to a file creating the file if it does not exist. 3217 * 3218 * @param file the file to write 3219 * @param data the content to write to the file 3220 * @param charsetName the name of the requested charset, {@code null} means platform default 3221 * @throws IOException in case of an I/O error 3222 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3223 * @since 2.0 3224 */ write(final File file, final CharSequence data, final String charsetName)3225 public static void write(final File file, final CharSequence data, final String charsetName) throws IOException { 3226 write(file, data, charsetName, false); 3227 } 3228 3229 /** 3230 * Writes a CharSequence to a file creating the file if it does not exist. 3231 * 3232 * @param file the file to write 3233 * @param data the content to write to the file 3234 * @param charsetName the name of the requested charset, {@code null} means platform default 3235 * @param append if {@code true}, then the data will be added to the 3236 * end of the file rather than overwriting 3237 * @throws IOException in case of an I/O error 3238 * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io 3239 * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM 3240 * @since 2.1 3241 */ write(final File file, final CharSequence data, final String charsetName, final boolean append)3242 public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) throws IOException { 3243 write(file, data, Charsets.toCharset(charsetName), append); 3244 } 3245 3246 // Must be called with a directory 3247 3248 /** 3249 * Writes a byte array to a file creating the file if it does not exist. 3250 * <p> 3251 * NOTE: As from v1.3, the parent directories of the file will be created 3252 * if they do not exist. 3253 * </p> 3254 * 3255 * @param file the file to write to 3256 * @param data the content to write to the file 3257 * @throws IOException in case of an I/O error 3258 * @since 1.1 3259 */ writeByteArrayToFile(final File file, final byte[] data)3260 public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException { 3261 writeByteArrayToFile(file, data, false); 3262 } 3263 3264 /** 3265 * Writes a byte array to a file creating the file if it does not exist. 3266 * 3267 * @param file the file to write to 3268 * @param data the content to write to the file 3269 * @param append if {@code true}, then bytes will be added to the 3270 * end of the file rather than overwriting 3271 * @throws IOException in case of an I/O error 3272 * @since 2.1 3273 */ writeByteArrayToFile(final File file, final byte[] data, final boolean append)3274 public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException { 3275 writeByteArrayToFile(file, data, 0, data.length, append); 3276 } 3277 3278 /** 3279 * Writes {@code len} bytes from the specified byte array starting 3280 * at offset {@code off} to a file, creating the file if it does 3281 * not exist. 3282 * 3283 * @param file the file to write to 3284 * @param data the content to write to the file 3285 * @param off the start offset in the data 3286 * @param len the number of bytes to write 3287 * @throws IOException in case of an I/O error 3288 * @since 2.5 3289 */ writeByteArrayToFile(final File file, final byte[] data, final int off, final int len)3290 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException { 3291 writeByteArrayToFile(file, data, off, len, false); 3292 } 3293 3294 /** 3295 * Writes {@code len} bytes from the specified byte array starting 3296 * at offset {@code off} to a file, creating the file if it does 3297 * not exist. 3298 * 3299 * @param file the file to write to 3300 * @param data the content to write to the file 3301 * @param off the start offset in the data 3302 * @param len the number of bytes to write 3303 * @param append if {@code true}, then bytes will be added to the 3304 * end of the file rather than overwriting 3305 * @throws IOException in case of an I/O error 3306 * @since 2.5 3307 */ writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append)3308 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException { 3309 try (OutputStream out = newOutputStream(file, append)) { 3310 out.write(data, off, len); 3311 } 3312 } 3313 3314 /** 3315 * Writes the {@code toString()} value of each item in a collection to 3316 * the specified {@link File} line by line. 3317 * The default VM encoding and the default line ending will be used. 3318 * 3319 * @param file the file to write to 3320 * @param lines the lines to write, {@code null} entries produce blank lines 3321 * @throws IOException in case of an I/O error 3322 * @since 1.3 3323 */ writeLines(final File file, final Collection<?> lines)3324 public static void writeLines(final File file, final Collection<?> lines) throws IOException { 3325 writeLines(file, null, lines, null, false); 3326 } 3327 3328 /** 3329 * Writes the {@code toString()} value of each item in a collection to 3330 * the specified {@link File} line by line. 3331 * The default VM encoding and the default line ending will be used. 3332 * 3333 * @param file the file to write to 3334 * @param lines the lines to write, {@code null} entries produce blank lines 3335 * @param append if {@code true}, then the lines will be added to the 3336 * end of the file rather than overwriting 3337 * @throws IOException in case of an I/O error 3338 * @since 2.1 3339 */ writeLines(final File file, final Collection<?> lines, final boolean append)3340 public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException { 3341 writeLines(file, null, lines, null, append); 3342 } 3343 3344 /** 3345 * Writes the {@code toString()} value of each item in a collection to 3346 * the specified {@link File} line by line. 3347 * The default VM encoding and the specified line ending will be used. 3348 * 3349 * @param file the file to write to 3350 * @param lines the lines to write, {@code null} entries produce blank lines 3351 * @param lineEnding the line separator to use, {@code null} is system default 3352 * @throws IOException in case of an I/O error 3353 * @since 1.3 3354 */ writeLines(final File file, final Collection<?> lines, final String lineEnding)3355 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException { 3356 writeLines(file, null, lines, lineEnding, false); 3357 } 3358 3359 /** 3360 * Writes the {@code toString()} value of each item in a collection to 3361 * the specified {@link File} line by line. 3362 * The default VM encoding and the specified line ending will be used. 3363 * 3364 * @param file the file to write to 3365 * @param lines the lines to write, {@code null} entries produce blank lines 3366 * @param lineEnding the line separator to use, {@code null} is system default 3367 * @param append if {@code true}, then the lines will be added to the 3368 * end of the file rather than overwriting 3369 * @throws IOException in case of an I/O error 3370 * @since 2.1 3371 */ writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append)3372 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException { 3373 writeLines(file, null, lines, lineEnding, append); 3374 } 3375 3376 /** 3377 * Writes the {@code toString()} value of each item in a collection to 3378 * the specified {@link File} line by line. 3379 * The specified character encoding and the default line ending will be used. 3380 * <p> 3381 * NOTE: As from v1.3, the parent directories of the file will be created 3382 * if they do not exist. 3383 * </p> 3384 * 3385 * @param file the file to write to 3386 * @param charsetName the name of the requested charset, {@code null} means platform default 3387 * @param lines the lines to write, {@code null} entries produce blank lines 3388 * @throws IOException in case of an I/O error 3389 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3390 * @since 1.1 3391 */ writeLines(final File file, final String charsetName, final Collection<?> lines)3392 public static void writeLines(final File file, final String charsetName, final Collection<?> lines) throws IOException { 3393 writeLines(file, charsetName, lines, null, false); 3394 } 3395 3396 /** 3397 * Writes the {@code toString()} value of each item in a collection to 3398 * the specified {@link File} line by line, optionally appending. 3399 * The specified character encoding and the default line ending will be used. 3400 * 3401 * @param file the file to write to 3402 * @param charsetName the name of the requested charset, {@code null} means platform default 3403 * @param lines the lines to write, {@code null} entries produce blank lines 3404 * @param append if {@code true}, then the lines will be added to the 3405 * end of the file rather than overwriting 3406 * @throws IOException in case of an I/O error 3407 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3408 * @since 2.1 3409 */ writeLines(final File file, final String charsetName, final Collection<?> lines, final boolean append)3410 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final boolean append) throws IOException { 3411 writeLines(file, charsetName, lines, null, append); 3412 } 3413 3414 /** 3415 * Writes the {@code toString()} value of each item in a collection to 3416 * the specified {@link File} line by line. 3417 * The specified character encoding and the line ending will be used. 3418 * <p> 3419 * NOTE: As from v1.3, the parent directories of the file will be created 3420 * if they do not exist. 3421 * </p> 3422 * 3423 * @param file the file to write to 3424 * @param charsetName the name of the requested charset, {@code null} means platform default 3425 * @param lines the lines to write, {@code null} entries produce blank lines 3426 * @param lineEnding the line separator to use, {@code null} is system default 3427 * @throws IOException in case of an I/O error 3428 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3429 * @since 1.1 3430 */ writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding)3431 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding) throws IOException { 3432 writeLines(file, charsetName, lines, lineEnding, false); 3433 } 3434 3435 /** 3436 * Writes the {@code toString()} value of each item in a collection to 3437 * the specified {@link File} line by line. 3438 * The specified character encoding and the line ending will be used. 3439 * 3440 * @param file the file to write to 3441 * @param charsetName the name of the requested charset, {@code null} means platform default 3442 * @param lines the lines to write, {@code null} entries produce blank lines 3443 * @param lineEnding the line separator to use, {@code null} is system default 3444 * @param append if {@code true}, then the lines will be added to the 3445 * end of the file rather than overwriting 3446 * @throws IOException in case of an I/O error 3447 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3448 * @since 2.1 3449 */ writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding, final boolean append)3450 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding, final boolean append) 3451 throws IOException { 3452 try (OutputStream out = new BufferedOutputStream(newOutputStream(file, append))) { 3453 IOUtils.writeLines(lines, lineEnding, out, charsetName); 3454 } 3455 } 3456 3457 /** 3458 * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. 3459 * 3460 * @param file the file to write 3461 * @param data the content to write to the file 3462 * @throws IOException in case of an I/O error 3463 * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding) 3464 */ 3465 @Deprecated writeStringToFile(final File file, final String data)3466 public static void writeStringToFile(final File file, final String data) throws IOException { 3467 writeStringToFile(file, data, Charset.defaultCharset(), false); 3468 } 3469 3470 /** 3471 * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. 3472 * 3473 * @param file the file to write 3474 * @param data the content to write to the file 3475 * @param append if {@code true}, then the String will be added to the 3476 * end of the file rather than overwriting 3477 * @throws IOException in case of an I/O error 3478 * @since 2.1 3479 * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding) 3480 */ 3481 @Deprecated writeStringToFile(final File file, final String data, final boolean append)3482 public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException { 3483 writeStringToFile(file, data, Charset.defaultCharset(), append); 3484 } 3485 3486 /** 3487 * Writes a String to a file creating the file if it does not exist. 3488 * <p> 3489 * NOTE: As from v1.3, the parent directories of the file will be created 3490 * if they do not exist. 3491 * </p> 3492 * 3493 * @param file the file to write 3494 * @param data the content to write to the file 3495 * @param charset the charset to use, {@code null} means platform default 3496 * @throws IOException in case of an I/O error 3497 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3498 * @since 2.4 3499 */ writeStringToFile(final File file, final String data, final Charset charset)3500 public static void writeStringToFile(final File file, final String data, final Charset charset) throws IOException { 3501 writeStringToFile(file, data, charset, false); 3502 } 3503 3504 /** 3505 * Writes a String to a file creating the file if it does not exist. 3506 * 3507 * @param file the file to write 3508 * @param data the content to write to the file 3509 * @param charset the charset to use, {@code null} means platform default 3510 * @param append if {@code true}, then the String will be added to the 3511 * end of the file rather than overwriting 3512 * @throws IOException in case of an I/O error 3513 * @since 2.3 3514 */ writeStringToFile(final File file, final String data, final Charset charset, final boolean append)3515 public static void writeStringToFile(final File file, final String data, final Charset charset, final boolean append) throws IOException { 3516 try (OutputStream out = newOutputStream(file, append)) { 3517 IOUtils.write(data, out, charset); 3518 } 3519 } 3520 3521 /** 3522 * Writes a String to a file creating the file if it does not exist. 3523 * <p> 3524 * NOTE: As from v1.3, the parent directories of the file will be created 3525 * if they do not exist. 3526 * </p> 3527 * 3528 * @param file the file to write 3529 * @param data the content to write to the file 3530 * @param charsetName the name of the requested charset, {@code null} means platform default 3531 * @throws IOException in case of an I/O error 3532 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3533 */ writeStringToFile(final File file, final String data, final String charsetName)3534 public static void writeStringToFile(final File file, final String data, final String charsetName) throws IOException { 3535 writeStringToFile(file, data, charsetName, false); 3536 } 3537 3538 /** 3539 * Writes a String to a file creating the file if it does not exist. 3540 * 3541 * @param file the file to write 3542 * @param data the content to write to the file 3543 * @param charsetName the name of the requested charset, {@code null} means platform default 3544 * @param append if {@code true}, then the String will be added to the 3545 * end of the file rather than overwriting 3546 * @throws IOException in case of an I/O error 3547 * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io 3548 * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM 3549 * @since 2.1 3550 */ writeStringToFile(final File file, final String data, final String charsetName, final boolean append)3551 public static void writeStringToFile(final File file, final String data, final String charsetName, final boolean append) throws IOException { 3552 writeStringToFile(file, data, Charsets.toCharset(charsetName), append); 3553 } 3554 3555 /** 3556 * Instances should NOT be constructed in standard programming. 3557 * @deprecated Will be private in 3.0. 3558 */ 3559 @Deprecated FileUtils()3560 public FileUtils() { //NOSONAR 3561 3562 } 3563 3564 } 3565