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