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