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