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