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.getAsBoolean(() -> 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.getAsBoolean(() -> 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.getAsBoolean(() -> 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.getAsBoolean(() -> 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.getAsBoolean(() -> 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.getAsBoolean(() -> 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.getAsBoolean(() -> 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 // @formatter:off 2286 final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.builder() 2287 .setPathCounters(Counters.noopPathCounters()) 2288 .setFileFilter(fileFilter) 2289 .setDirectoryFilter(dirPathFilter) 2290 .setVisitFileFailedFunction((p, e) -> FileVisitResult.CONTINUE) 2291 .get(); 2292 // @formatter:on 2293 final Set<FileVisitOption> optionSet = new HashSet<>(); 2294 if (options != null) { 2295 Collections.addAll(optionSet, options); 2296 } 2297 Files.walkFileTree(directory.toPath(), optionSet, toMaxDepth(isDirFilterSet), visitor); 2298 return visitor; 2299 } 2300 2301 /** 2302 * Lists files in a directory, asserting that the supplied directory exists and is a directory. 2303 * 2304 * @param directory The directory to list. 2305 * @param fileFilter Optional file filter, may be null. 2306 * @return The files in the directory, never {@code null}. 2307 * @throws NullPointerException if the {@code directory} is {@code null}. 2308 * @throws IllegalArgumentException if the {@code directory} exists but is not a directory. 2309 * @throws IOException if an I/O error occurs per {@link File#listFiles()} and {@link File#listFiles(FileFilter)}. 2310 * @throws SecurityException If a security manager exists and its {@link SecurityManager#checkRead(String)} method denies read access to the 2311 * directory. 2312 */ 2313 private static File[] listFiles(final File directory, final FileFilter fileFilter) throws IOException { 2314 requireDirectoryExists(directory, "directory"); 2315 final File[] files = directory.listFiles(fileFilter); 2316 if (files == null) { 2317 // null if the directory does not denote a directory, or if an I/O error occurs. 2318 throw new IOException("Unknown I/O error listing contents of directory: " + directory); 2319 } 2320 return files; 2321 } 2322 2323 /** 2324 * Finds files within a given directory (and optionally its 2325 * subdirectories). All files found are filtered by an IOFileFilter. 2326 * <p> 2327 * If your search should recurse into subdirectories you can pass in 2328 * an IOFileFilter for directories. You don't need to bind a 2329 * DirectoryFileFilter (via logical AND) to this filter. This method does 2330 * that for you. 2331 * </p> 2332 * <p> 2333 * An example: If you want to search through all directories called 2334 * "temp" you pass in {@code FileFilterUtils.NameFileFilter("temp")} 2335 * </p> 2336 * <p> 2337 * Another common usage of this method is find files in a directory 2338 * tree but ignoring the directories generated CVS. You can simply pass 2339 * in {@code FileFilterUtils.makeCVSAware(null)}. 2340 * </p> 2341 * 2342 * @param directory the directory to search in 2343 * @param fileFilter filter to apply when finding files. Must not be {@code null}, 2344 * use {@link TrueFileFilter#INSTANCE} to match all files in selected directories. 2345 * @param dirFilter optional filter to apply when finding subdirectories. 2346 * If this parameter is {@code null}, subdirectories will not be included in the 2347 * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. 2348 * @return a collection of {@link File} with the matching files 2349 * @see org.apache.commons.io.filefilter.FileFilterUtils 2350 * @see org.apache.commons.io.filefilter.NameFileFilter 2351 */ 2352 public static Collection<File> listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 2353 final AccumulatorPathVisitor visitor = Uncheck 2354 .apply(d -> listAccumulate(d, FileFileFilter.INSTANCE.and(fileFilter), dirFilter, FileVisitOption.FOLLOW_LINKS), directory); 2355 return toList(visitor.getFileList().stream().map(Path::toFile)); 2356 } 2357 2358 /** 2359 * Lists Files in the given {@code directory}, adding each file to the given list. 2360 * 2361 * @param directory A File for an assumed directory, not null. 2362 * @param files The list to add found Files, not null. 2363 * @param recursive Whether or not to recurse into subdirectories. 2364 * @param filter How to filter files, not null. 2365 */ 2366 @SuppressWarnings("null") 2367 private static void listFiles(final File directory, final List<File> files, final boolean recursive, final FilenameFilter filter) { 2368 final File[] listFiles = directory.listFiles(); 2369 if (listFiles != null) { 2370 // Only allocate if you must. 2371 final List<File> dirs = recursive ? new ArrayList<>() : null; 2372 Arrays.stream(listFiles).forEach(f -> { 2373 if (recursive && f.isDirectory()) { 2374 dirs.add(f); 2375 } else if (f.isFile() && filter.accept(directory, f.getName())) { 2376 files.add(f); 2377 } 2378 }); 2379 if (recursive) { 2380 dirs.forEach(d -> listFiles(d, files, true, filter)); 2381 } 2382 } 2383 } 2384 2385 /** 2386 * Lists files within a given directory (and optionally its subdirectories) 2387 * which match an array of extensions. 2388 * 2389 * @param directory the directory to search in 2390 * @param extensions an array of extensions, for example, {"java","xml"}. If this 2391 * parameter is {@code null}, all files are returned. 2392 * @param recursive if true all subdirectories are searched as well 2393 * @return a collection of {@link File} with the matching files 2394 */ 2395 public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) { 2396 // IO-856: Don't use NIO to path walk, allocate as little as possible while traversing. 2397 final List<File> files = new ArrayList<>(); 2398 final FilenameFilter filter = extensions != null ? toSuffixFileFilter(extensions) : TrueFileFilter.INSTANCE; 2399 listFiles(directory, files, recursive, filter); 2400 return files; 2401 } 2402 2403 /** 2404 * Finds files within a given directory (and optionally its 2405 * subdirectories). All files found are filtered by an IOFileFilter. 2406 * <p> 2407 * The resulting collection includes the starting directory and 2408 * any subdirectories that match the directory filter. 2409 * </p> 2410 * 2411 * @param directory the directory to search in 2412 * @param fileFilter filter to apply when finding files. 2413 * @param dirFilter optional filter to apply when finding subdirectories. 2414 * If this parameter is {@code null}, subdirectories will not be included in the 2415 * search. Use TrueFileFilter.INSTANCE to match all directories. 2416 * @return a collection of {@link File} with the matching files 2417 * @see org.apache.commons.io.FileUtils#listFiles 2418 * @see org.apache.commons.io.filefilter.FileFilterUtils 2419 * @see org.apache.commons.io.filefilter.NameFileFilter 2420 * @since 2.2 2421 */ 2422 public static Collection<File> listFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { 2423 final AccumulatorPathVisitor visitor = Uncheck.apply(d -> listAccumulate(d, fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS), 2424 directory); 2425 final List<Path> list = visitor.getFileList(); 2426 list.addAll(visitor.getDirList()); 2427 return toList(list.stream().map(Path::toFile)); 2428 } 2429 2430 /** 2431 * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure. 2432 * <p> 2433 * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is 2434 * null, nothing happens. 2435 * </p> 2436 * 2437 * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens. 2438 * @return the given directory. 2439 * @throws IOException if the directory was not created along with all its parent directories. 2440 * @throws IOException if the given file object is not a directory. 2441 * @throws SecurityException See {@link File#mkdirs()}. 2442 * @see File#mkdirs() 2443 */ 2444 private static File mkdirs(final File directory) throws IOException { 2445 if (directory != null && !directory.mkdirs() && !directory.isDirectory()) { 2446 throw new IOException("Cannot create directory '" + directory + "'."); 2447 } 2448 return directory; 2449 } 2450 2451 /** 2452 * Moves a directory. 2453 * <p> 2454 * When the destination directory is on another file system, do a "copy and delete". 2455 * </p> 2456 * 2457 * @param srcDir the directory to be moved. 2458 * @param destDir the destination directory. 2459 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2460 * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory 2461 * @throws FileNotFoundException if the source does not exist. 2462 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2463 * @since 1.4 2464 */ 2465 public static void moveDirectory(final File srcDir, final File destDir) throws IOException { 2466 Objects.requireNonNull(destDir, "destination"); 2467 requireDirectoryExists(srcDir, "srcDir"); 2468 requireAbsent(destDir, "destDir"); 2469 if (!srcDir.renameTo(destDir)) { 2470 if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) { 2471 throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir); 2472 } 2473 copyDirectory(srcDir, destDir); 2474 deleteDirectory(srcDir); 2475 if (srcDir.exists()) { 2476 throw new IOException("Failed to delete original directory '" + srcDir + 2477 "' after copy to '" + destDir + "'"); 2478 } 2479 } 2480 } 2481 2482 /** 2483 * Moves a directory to another directory. 2484 * <p> 2485 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2486 * </p> 2487 * 2488 * @param source the directory to be moved. 2489 * @param destDir the destination file. 2490 * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an 2491 * IOException. 2492 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2493 * @throws IllegalArgumentException if the source or destination is invalid. 2494 * @throws FileNotFoundException if the source does not exist. 2495 * @throws IOException if the directory was not created along with all its parent directories, if enabled. 2496 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2497 * @throws SecurityException See {@link File#mkdirs()}. 2498 * @since 1.4 2499 */ 2500 public static void moveDirectoryToDirectory(final File source, final File destDir, final boolean createDestDir) throws IOException { 2501 validateMoveParameters(source, destDir); 2502 if (!destDir.isDirectory()) { 2503 if (destDir.exists()) { 2504 throw new IOException("Destination '" + destDir + "' is not a directory"); 2505 } 2506 if (!createDestDir) { 2507 throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + false + "]"); 2508 } 2509 mkdirs(destDir); 2510 } 2511 moveDirectory(source, new File(destDir, source.getName())); 2512 } 2513 2514 /** 2515 * Moves a file preserving attributes. 2516 * <p> 2517 * Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}. 2518 * </p> 2519 * <p> 2520 * When the destination file is on another file system, do a "copy and delete". 2521 * </p> 2522 * 2523 * @param srcFile the file to be moved. 2524 * @param destFile the destination file. 2525 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2526 * @throws FileExistsException if the destination file exists. 2527 * @throws FileNotFoundException if the source file does not exist. 2528 * @throws IllegalArgumentException if {@code srcFile} is a directory 2529 * @throws IOException if an error occurs. 2530 * @since 1.4 2531 */ 2532 public static void moveFile(final File srcFile, final File destFile) throws IOException { 2533 moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES); 2534 } 2535 2536 /** 2537 * Moves a file. 2538 * <p> 2539 * When the destination file is on another file system, do a "copy and delete". 2540 * </p> 2541 * 2542 * @param srcFile the file to be moved. 2543 * @param destFile the destination file. 2544 * @param copyOptions Copy options. 2545 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2546 * @throws FileExistsException if the destination file exists. 2547 * @throws FileNotFoundException if the source file does not exist. 2548 * @throws IllegalArgumentException if {@code srcFile} is a directory 2549 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2550 * @since 2.9.0 2551 */ 2552 public static void moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException { 2553 Objects.requireNonNull(destFile, "destination"); 2554 checkFileExists(srcFile, "srcFile"); 2555 requireAbsent(destFile, "destFile"); 2556 final boolean rename = srcFile.renameTo(destFile); 2557 if (!rename) { 2558 // Don't interfere with file date on move, handled by StandardCopyOption.COPY_ATTRIBUTES 2559 copyFile(srcFile, destFile, false, copyOptions); 2560 if (!srcFile.delete()) { 2561 deleteQuietly(destFile); 2562 throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'"); 2563 } 2564 } 2565 } 2566 2567 /** 2568 * Moves a file into a directory. 2569 * <p> 2570 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2571 * </p> 2572 * 2573 * @param srcFile the file to be moved. 2574 * @param destDir the directory to move the file into 2575 * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an 2576 * IOException if the destination directory does not already exist. 2577 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2578 * @throws FileExistsException if the destination file exists. 2579 * @throws FileNotFoundException if the source file does not exist. 2580 * @throws IOException if source or destination is invalid. 2581 * @throws IOException if the directory was not created along with all its parent directories, if enabled. 2582 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2583 * @throws SecurityException See {@link File#mkdirs()}. 2584 * @throws IllegalArgumentException if {@code destDir} exists but is not a directory 2585 * @since 1.4 2586 */ 2587 public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException { 2588 validateMoveParameters(srcFile, destDir); 2589 if (!destDir.exists() && createDestDir) { 2590 mkdirs(destDir); 2591 } 2592 requireDirectoryExists(destDir, "destDir"); 2593 moveFile(srcFile, new File(destDir, srcFile.getName())); 2594 } 2595 2596 /** 2597 * Moves a file or directory into a destination directory. 2598 * <p> 2599 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories. 2600 * </p> 2601 * <p> 2602 * When the destination is on another file system, do a "copy and delete". 2603 * </p> 2604 * 2605 * @param src the file or directory to be moved. 2606 * @param destDir the destination directory. 2607 * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an 2608 * IOException if the destination directory does not already exist. 2609 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 2610 * @throws FileExistsException if the directory or file exists in the destination directory. 2611 * @throws FileNotFoundException if the source file does not exist. 2612 * @throws IOException if source or destination is invalid. 2613 * @throws IOException if an error occurs or setting the last-modified time didn't succeed. 2614 * @since 1.4 2615 */ 2616 public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException { 2617 validateMoveParameters(src, destDir); 2618 if (src.isDirectory()) { 2619 moveDirectoryToDirectory(src, destDir, createDestDir); 2620 } else { 2621 moveFileToDirectory(src, destDir, createDestDir); 2622 } 2623 } 2624 2625 /** 2626 * Creates a new OutputStream by opening or creating a file, returning an output stream that may be used to write bytes 2627 * to the file. 2628 * 2629 * @param append Whether or not to append. 2630 * @param file the File. 2631 * @return a new OutputStream. 2632 * @throws IOException if an I/O error occurs. 2633 * @see PathUtils#newOutputStream(Path, boolean) 2634 * @since 2.12.0 2635 */ 2636 public static OutputStream newOutputStream(final File file, final boolean append) throws IOException { 2637 return PathUtils.newOutputStream(Objects.requireNonNull(file, PROTOCOL_FILE).toPath(), append); 2638 } 2639 2640 /** 2641 * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling 2642 * {@code new FileInputStream(file)}. 2643 * <p> 2644 * At the end of the method either the stream will be successfully opened, or an exception will have been thrown. 2645 * </p> 2646 * <p> 2647 * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a 2648 * directory. An exception is thrown if the file exists but cannot be read. 2649 * </p> 2650 * 2651 * @param file the file to open for input, must not be {@code null} 2652 * @return a new {@link FileInputStream} for the specified file 2653 * @throws NullPointerException if file is {@code null}. 2654 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some 2655 * other reason cannot be opened for reading. 2656 * @throws IOException See FileNotFoundException above, FileNotFoundException is a subclass of IOException. 2657 * @since 1.3 2658 */ 2659 public static FileInputStream openInputStream(final File file) throws IOException { 2660 Objects.requireNonNull(file, PROTOCOL_FILE); 2661 return new FileInputStream(file); 2662 } 2663 2664 /** 2665 * Opens a {@link FileOutputStream} for the specified file, checking and 2666 * creating the parent directory if it does not exist. 2667 * <p> 2668 * At the end of the method either the stream will be successfully opened, 2669 * or an exception will have been thrown. 2670 * </p> 2671 * <p> 2672 * The parent directory will be created if it does not exist. 2673 * The file will be created if it does not exist. 2674 * An exception is thrown if the file object exists but is a directory. 2675 * An exception is thrown if the file exists but cannot be written to. 2676 * An exception is thrown if the parent directory cannot be created. 2677 * </p> 2678 * 2679 * @param file the file to open for output, must not be {@code null} 2680 * @return a new {@link FileOutputStream} for the specified file 2681 * @throws NullPointerException if the file object is {@code null}. 2682 * @throws IllegalArgumentException if the file object is a directory 2683 * @throws IllegalArgumentException if the file is not writable. 2684 * @throws IOException if the directories could not be created. 2685 * @since 1.3 2686 */ 2687 public static FileOutputStream openOutputStream(final File file) throws IOException { 2688 return openOutputStream(file, false); 2689 } 2690 2691 /** 2692 * Opens a {@link FileOutputStream} for the specified file, checking and 2693 * creating the parent directory if it does not exist. 2694 * <p> 2695 * At the end of the method either the stream will be successfully opened, 2696 * or an exception will have been thrown. 2697 * </p> 2698 * <p> 2699 * The parent directory will be created if it does not exist. 2700 * The file will be created if it does not exist. 2701 * An exception is thrown if the file object exists but is a directory. 2702 * An exception is thrown if the file exists but cannot be written to. 2703 * An exception is thrown if the parent directory cannot be created. 2704 * </p> 2705 * 2706 * @param file the file to open for output, must not be {@code null} 2707 * @param append if {@code true}, then bytes will be added to the 2708 * end of the file rather than overwriting 2709 * @return a new {@link FileOutputStream} for the specified file 2710 * @throws NullPointerException if the file object is {@code null}. 2711 * @throws IllegalArgumentException if the file object is a directory 2712 * @throws IOException if the directories could not be created, or the file is not writable 2713 * @since 2.1 2714 */ 2715 public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException { 2716 Objects.requireNonNull(file, PROTOCOL_FILE); 2717 if (file.exists()) { 2718 checkIsFile(file, PROTOCOL_FILE); 2719 } else { 2720 createParentDirectories(file); 2721 } 2722 return new FileOutputStream(file, append); 2723 } 2724 2725 /** 2726 * Reads the contents of a file into a byte array. 2727 * The file is always closed. 2728 * 2729 * @param file the file to read, must not be {@code null} 2730 * @return the file contents, never {@code null} 2731 * @throws NullPointerException if file is {@code null}. 2732 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2733 * regular file, or for some other reason why the file cannot be opened for reading. 2734 * @since 1.1 2735 */ 2736 public static byte[] readFileToByteArray(final File file) throws IOException { 2737 Objects.requireNonNull(file, PROTOCOL_FILE); 2738 return Files.readAllBytes(file.toPath()); 2739 } 2740 2741 /** 2742 * Reads the contents of a file into a String using the virtual machine's {@link Charset#defaultCharset() default charset}. The 2743 * file is always closed. 2744 * 2745 * @param file the file to read, must not be {@code null} 2746 * @return the file contents, never {@code null} 2747 * @throws NullPointerException if file is {@code null}. 2748 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a regular file, or for some other 2749 * reason why the file cannot be opened for reading. 2750 * @since 1.3.1 2751 * @deprecated Use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) 2752 */ 2753 @Deprecated 2754 public static String readFileToString(final File file) throws IOException { 2755 return readFileToString(file, Charset.defaultCharset()); 2756 } 2757 2758 /** 2759 * Reads the contents of a file into a String. 2760 * The file is always closed. 2761 * 2762 * @param file the file to read, must not be {@code null} 2763 * @param charsetName the name of the requested charset, {@code null} means platform default 2764 * @return the file contents, never {@code null} 2765 * @throws NullPointerException if file is {@code null}. 2766 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2767 * regular file, or for some other reason why the file cannot be opened for reading. 2768 * @since 2.3 2769 */ 2770 public static String readFileToString(final File file, final Charset charsetName) throws IOException { 2771 return IOUtils.toString(() -> Files.newInputStream(file.toPath()), Charsets.toCharset(charsetName)); 2772 } 2773 2774 /** 2775 * Reads the contents of a file into a String. The file is always closed. 2776 * 2777 * @param file the file to read, must not be {@code null} 2778 * @param charsetName the name of the requested charset, {@code null} means platform default 2779 * @return the file contents, never {@code null} 2780 * @throws NullPointerException if file is {@code null}. 2781 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2782 * regular file, or for some other reason why the file cannot be opened for reading. 2783 * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable. 2784 * @since 2.3 2785 */ 2786 public static String readFileToString(final File file, final String charsetName) throws IOException { 2787 return readFileToString(file, Charsets.toCharset(charsetName)); 2788 } 2789 2790 /** 2791 * Reads the contents of a file line by line to a List of Strings using the virtual machine's {@link Charset#defaultCharset() default charset}. 2792 * The file is always closed. 2793 * 2794 * @param file the file to read, must not be {@code null} 2795 * @return the list of Strings representing each line in the file, never {@code null} 2796 * @throws NullPointerException if file is {@code null}. 2797 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a regular file, or for some other 2798 * reason why the file cannot be opened for reading. 2799 * @since 1.3 2800 * @deprecated Use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) 2801 */ 2802 @Deprecated 2803 public static List<String> readLines(final File file) throws IOException { 2804 return readLines(file, Charset.defaultCharset()); 2805 } 2806 2807 /** 2808 * Reads the contents of a file line by line to a List of Strings. 2809 * The file is always closed. 2810 * 2811 * @param file the file to read, must not be {@code null} 2812 * @param charset the charset to use, {@code null} means platform default 2813 * @return the list of Strings representing each line in the file, never {@code null} 2814 * @throws NullPointerException if file is {@code null}. 2815 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2816 * regular file, or for some other reason why the file cannot be opened for reading. 2817 * @since 2.3 2818 */ 2819 public static List<String> readLines(final File file, final Charset charset) throws IOException { 2820 return Files.readAllLines(file.toPath(), charset); 2821 } 2822 2823 /** 2824 * Reads the contents of a file line by line to a List of Strings. The file is always closed. 2825 * 2826 * @param file the file to read, must not be {@code null} 2827 * @param charsetName the name of the requested charset, {@code null} means platform default 2828 * @return the list of Strings representing each line in the file, never {@code null} 2829 * @throws NullPointerException if file is {@code null}. 2830 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a 2831 * regular file, or for some other reason why the file cannot be opened for reading. 2832 * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable. 2833 * @since 1.1 2834 */ 2835 public static List<String> readLines(final File file, final String charsetName) throws IOException { 2836 return readLines(file, Charsets.toCharset(charsetName)); 2837 } 2838 2839 private static void requireAbsent(final File file, final String name) throws FileExistsException { 2840 if (file.exists()) { 2841 throw new FileExistsException(String.format("File element in parameter '%s' already exists: '%s'", name, file)); 2842 } 2843 } 2844 2845 /** 2846 * Throws IllegalArgumentException if the given files' canonical representations are equal. 2847 * 2848 * @param file1 The first file to compare. 2849 * @param file2 The second file to compare. 2850 * @throws IOException if an I/O error occurs. 2851 * @throws IllegalArgumentException if the given files' canonical representations are equal. 2852 */ 2853 private static void requireCanonicalPathsNotEquals(final File file1, final File file2) throws IOException { 2854 final String canonicalPath = file1.getCanonicalPath(); 2855 if (canonicalPath.equals(file2.getCanonicalPath())) { 2856 throw new IllegalArgumentException(String 2857 .format("File canonical paths are equal: '%s' (file1='%s', file2='%s')", canonicalPath, file1, file2)); 2858 } 2859 } 2860 2861 /** 2862 * Requires that the given {@link File} exists and is a directory. 2863 * 2864 * @param directory The {@link File} to check. 2865 * @param name The parameter name to use in the exception message in case of null input or if the file is not a directory. 2866 * @throws NullPointerException if the given {@link File} is {@code null}. 2867 * @throws FileNotFoundException if the given {@link File} does not exist 2868 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory. 2869 */ 2870 private static void requireDirectoryExists(final File directory, final String name) throws FileNotFoundException { 2871 Objects.requireNonNull(directory, name); 2872 if (!directory.isDirectory()) { 2873 if (directory.exists()) { 2874 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'"); 2875 } 2876 throw new FileNotFoundException("Directory '" + directory + "' does not exist."); 2877 } 2878 } 2879 2880 /** 2881 * Requires that the given {@link File} is a directory if it exists. 2882 * 2883 * @param directory The {@link File} to check. 2884 * @param name The parameter name to use in the exception message in case of null input. 2885 * @throws NullPointerException if the given {@link File} is {@code null}. 2886 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory. 2887 */ 2888 private static void requireDirectoryIfExists(final File directory, final String name) { 2889 Objects.requireNonNull(directory, name); 2890 if (directory.exists() && !directory.isDirectory()) { 2891 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'"); 2892 } 2893 } 2894 2895 /** 2896 * Sets file lastModifiedTime, lastAccessTime and creationTime to match source file 2897 * 2898 * @param sourceFile The source file to query. 2899 * @param targetFile The target file or directory to set. 2900 * @return {@code true} if and only if the operation succeeded; 2901 * {@code false} otherwise 2902 * @throws NullPointerException if sourceFile is {@code null}. 2903 * @throws NullPointerException if targetFile is {@code null}. 2904 */ 2905 private static boolean setTimes(final File sourceFile, final File targetFile) { 2906 Objects.requireNonNull(sourceFile, "sourceFile"); 2907 Objects.requireNonNull(targetFile, "targetFile"); 2908 try { 2909 // Set creation, modified, last accessed to match source file 2910 final BasicFileAttributes srcAttr = Files.readAttributes(sourceFile.toPath(), BasicFileAttributes.class); 2911 final BasicFileAttributeView destAttrView = Files.getFileAttributeView(targetFile.toPath(), BasicFileAttributeView.class); 2912 // null guards are not needed; BasicFileAttributes.setTimes(...) is null safe 2913 destAttrView.setTimes(srcAttr.lastModifiedTime(), srcAttr.lastAccessTime(), srcAttr.creationTime()); 2914 return true; 2915 } catch (final IOException ignored) { 2916 // Fallback: Only set modified time to match source file 2917 return targetFile.setLastModified(sourceFile.lastModified()); 2918 } 2919 2920 // TODO: (Help!) Determine historically why setLastModified(File, File) needed PathUtils.setLastModifiedTime() if 2921 // sourceFile.isFile() was true, but needed setLastModifiedTime(File, long) if sourceFile.isFile() was false 2922 } 2923 2924 /** 2925 * Returns the size of the specified file or directory. If the provided 2926 * {@link File} is a regular file, then the file's length is returned. 2927 * If the argument is a directory, then the size of the directory is 2928 * calculated recursively. If a directory or subdirectory is security 2929 * restricted, its size will not be included. 2930 * <p> 2931 * Note that overflow is not detected, and the return value may be negative if 2932 * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative 2933 * method that does not overflow. 2934 * </p> 2935 * 2936 * @param file the regular file or directory to return the size 2937 * of (must not be {@code null}). 2938 * 2939 * @return the length of the file, or recursive size of the directory, 2940 * provided (in bytes). 2941 * 2942 * @throws NullPointerException if the file is {@code null}. 2943 * @throws IllegalArgumentException if the file does not exist. 2944 * @throws UncheckedIOException if an IO error occurs. 2945 * @since 2.0 2946 */ 2947 public static long sizeOf(final File file) { 2948 return Uncheck.getAsLong(() -> PathUtils.sizeOf(file.toPath())); 2949 } 2950 2951 /** 2952 * Returns the size of the specified file or directory. If the provided 2953 * {@link File} is a regular file, then the file's length is returned. 2954 * If the argument is a directory, then the size of the directory is 2955 * calculated recursively. If a directory or subdirectory is security 2956 * restricted, its size will not be included. 2957 * 2958 * @param file the regular file or directory to return the size 2959 * of (must not be {@code null}). 2960 * 2961 * @return the length of the file, or recursive size of the directory, 2962 * provided (in bytes). 2963 * 2964 * @throws NullPointerException if the file is {@code null}. 2965 * @throws IllegalArgumentException if the file does not exist. 2966 * @throws UncheckedIOException if an IO error occurs. 2967 * @since 2.4 2968 */ 2969 public static BigInteger sizeOfAsBigInteger(final File file) { 2970 return Uncheck.get(() -> PathUtils.sizeOfAsBigInteger(file.toPath())); 2971 } 2972 2973 /** 2974 * Counts the size of a directory recursively (sum of the length of all files). 2975 * <p> 2976 * Note that overflow is not detected, and the return value may be negative if 2977 * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative 2978 * method that does not overflow. 2979 * </p> 2980 * 2981 * @param directory directory to inspect, must not be {@code null}. 2982 * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total 2983 * is greater than {@link Long#MAX_VALUE}. 2984 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory 2985 * @throws NullPointerException if the directory is {@code null}. 2986 * @throws UncheckedIOException if an IO error occurs. 2987 */ 2988 public static long sizeOfDirectory(final File directory) { 2989 try { 2990 requireDirectoryExists(directory, "directory"); 2991 } catch (final FileNotFoundException e) { 2992 throw new UncheckedIOException(e); 2993 } 2994 return Uncheck.getAsLong(() -> PathUtils.sizeOfDirectory(directory.toPath())); 2995 } 2996 2997 /** 2998 * Counts the size of a directory recursively (sum of the length of all files). 2999 * 3000 * @param directory directory to inspect, must not be {@code null}. 3001 * @return size of directory in bytes, 0 if directory is security restricted. 3002 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory 3003 * @throws NullPointerException if the directory is {@code null}. 3004 * @throws UncheckedIOException if an IO error occurs. 3005 * @since 2.4 3006 */ 3007 public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) { 3008 try { 3009 requireDirectoryExists(directory, "directory"); 3010 } catch (final FileNotFoundException e) { 3011 throw new UncheckedIOException(e); 3012 } 3013 return Uncheck.get(() -> PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath())); 3014 } 3015 3016 /** 3017 * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions. 3018 * <p> 3019 * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a 3020 * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a 3021 * closed stream causes a {@link IllegalStateException}. 3022 * </p> 3023 * 3024 * @param directory the directory to search in 3025 * @param recursive if true all subdirectories are searched as well 3026 * @param extensions an array of extensions, for example, {"java","xml"}. If this parameter is {@code null}, all files are returned. 3027 * @return a Stream of {@link File} for matching files. 3028 * @throws IOException if an I/O error is thrown when accessing the starting file. 3029 * @since 2.9.0 3030 */ 3031 public static Stream<File> streamFiles(final File directory, final boolean recursive, final String... extensions) throws IOException { 3032 // @formatter:off 3033 final IOFileFilter filter = extensions == null 3034 ? FileFileFilter.INSTANCE 3035 : FileFileFilter.INSTANCE.and(toSuffixFileFilter(extensions)); 3036 // @formatter:on 3037 return PathUtils.walk(directory.toPath(), filter, toMaxDepth(recursive), false, FileVisitOption.FOLLOW_LINKS).map(Path::toFile); 3038 } 3039 3040 /** 3041 * Converts from a {@link URL} to a {@link File}. 3042 * <p> 3043 * Syntax such as {@code file:///my%20docs/file.txt} will be 3044 * correctly decoded to {@code /my docs/file.txt}. 3045 * UTF-8 is used to decode percent-encoded octets to characters. 3046 * Additionally, malformed percent-encoded octets are handled leniently by 3047 * passing them through literally. 3048 * </p> 3049 * 3050 * @param url the file URL to convert, {@code null} returns {@code null} 3051 * @return the equivalent {@link File} object, or {@code null} 3052 * if the URL's protocol is not {@code file} 3053 */ 3054 public static File toFile(final URL url) { 3055 if (url == null || !isFileProtocol(url)) { 3056 return null; 3057 } 3058 final String fileName = url.getFile().replace('/', File.separatorChar); 3059 return new File(decodeUrl(fileName)); 3060 } 3061 3062 /** 3063 * Converts each of an array of {@link URL} to a {@link File}. 3064 * <p> 3065 * Returns an array of the same size as the input. 3066 * If the input is {@code null}, an empty array is returned. 3067 * If the input contains {@code null}, the output array contains {@code null} at the same 3068 * index. 3069 * </p> 3070 * <p> 3071 * This method will decode the URL. 3072 * Syntax such as {@code file:///my%20docs/file.txt} will be 3073 * correctly decoded to {@code /my docs/file.txt}. 3074 * </p> 3075 * 3076 * @param urls the file URLs to convert, {@code null} returns empty array 3077 * @return a non-{@code null} array of Files matching the input, with a {@code null} item 3078 * if there was a {@code null} at that index in the input array 3079 * @throws IllegalArgumentException if any file is not a URL file 3080 * @throws IllegalArgumentException if any file is incorrectly encoded 3081 * @since 1.1 3082 */ 3083 public static File[] toFiles(final URL... urls) { 3084 if (IOUtils.length(urls) == 0) { 3085 return EMPTY_FILE_ARRAY; 3086 } 3087 final File[] files = new File[urls.length]; 3088 for (int i = 0; i < urls.length; i++) { 3089 final URL url = urls[i]; 3090 if (url != null) { 3091 if (!isFileProtocol(url)) { 3092 throw new IllegalArgumentException("Can only convert file URL to a File: " + url); 3093 } 3094 files[i] = toFile(url); 3095 } 3096 } 3097 return files; 3098 } 3099 3100 /** 3101 * Consumes all of the given stream. 3102 * <p> 3103 * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}. 3104 * </p> 3105 * 3106 * @param stream The stream to consume. 3107 * @return a new List. 3108 */ 3109 private static List<File> toList(final Stream<File> stream) { 3110 return stream.collect(Collectors.toList()); 3111 } 3112 3113 /** 3114 * Converts whether or not to recurse into a recursion max depth. 3115 * 3116 * @param recursive whether or not to recurse 3117 * @return the recursion depth 3118 */ 3119 private static int toMaxDepth(final boolean recursive) { 3120 return recursive ? Integer.MAX_VALUE : 1; 3121 } 3122 3123 /** 3124 * Converts an array of file extensions to suffixes. 3125 * 3126 * @param extensions an array of extensions. Format: {"java", "xml"} 3127 * @return an array of suffixes. Format: {".java", ".xml"} 3128 * @throws NullPointerException if the parameter is null 3129 */ 3130 private static String[] toSuffixes(final String... extensions) { 3131 return Stream.of(Objects.requireNonNull(extensions, "extensions")).map(s -> s.charAt(0) == '.' ? s : "." + s).toArray(String[]::new); 3132 } 3133 3134 private static SuffixFileFilter toSuffixFileFilter(final String... extensions) { 3135 return new SuffixFileFilter(toSuffixes(extensions)); 3136 } 3137 3138 /** 3139 * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just 3140 * updates the file's modified time. This method throws an IOException if the last modified date 3141 * of the file cannot be set. It creates parent directories if they do not exist. 3142 * 3143 * @param file the File to touch. 3144 * @throws NullPointerException if the parameter is {@code null}. 3145 * @throws IOException if setting the last-modified time failed or an I/O problem occurs. 3146 */ 3147 public static void touch(final File file) throws IOException { 3148 PathUtils.touch(Objects.requireNonNull(file, PROTOCOL_FILE).toPath()); 3149 } 3150 3151 /** 3152 * Converts each element of an array of {@link File} to a {@link URL}. 3153 * <p> 3154 * Returns an array of the same size as the input. 3155 * </p> 3156 * 3157 * @param files the files to convert, must not be {@code null} 3158 * @return an array of URLs matching the input 3159 * @throws IOException if a file cannot be converted 3160 * @throws NullPointerException if any argument is null 3161 */ 3162 public static URL[] toURLs(final File... files) throws IOException { 3163 Objects.requireNonNull(files, "files"); 3164 final URL[] urls = new URL[files.length]; 3165 for (int i = 0; i < urls.length; i++) { 3166 urls[i] = files[i].toURI().toURL(); 3167 } 3168 return urls; 3169 } 3170 3171 /** 3172 * Validates the given arguments. 3173 * <ul> 3174 * <li>Throws {@link NullPointerException} if {@code source} is null</li> 3175 * <li>Throws {@link NullPointerException} if {@code destination} is null</li> 3176 * <li>Throws {@link FileNotFoundException} if {@code source} does not exist</li> 3177 * </ul> 3178 * 3179 * @param source the file or directory to be moved. 3180 * @param destination the destination file or directory. 3181 * @throws NullPointerException if any of the given {@link File}s are {@code null}. 3182 * @throws FileNotFoundException if the source file does not exist. 3183 */ 3184 private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException { 3185 Objects.requireNonNull(source, "source"); 3186 Objects.requireNonNull(destination, "destination"); 3187 if (!source.exists()) { 3188 throw new FileNotFoundException("Source '" + source + "' does not exist"); 3189 } 3190 } 3191 3192 /** 3193 * Waits for the file system to detect a file's presence, with a timeout. 3194 * <p> 3195 * This method repeatedly tests {@link Files#exists(Path, LinkOption...)} until it returns 3196 * true up to the maximum time specified in seconds. 3197 * </p> 3198 * 3199 * @param file the file to check, must not be {@code null} 3200 * @param seconds the maximum time in seconds to wait 3201 * @return true if file exists 3202 * @throws NullPointerException if the file is {@code null} 3203 */ 3204 public static boolean waitFor(final File file, final int seconds) { 3205 Objects.requireNonNull(file, PROTOCOL_FILE); 3206 return PathUtils.waitFor(file.toPath(), Duration.ofSeconds(seconds), PathUtils.EMPTY_LINK_OPTION_ARRAY); 3207 } 3208 3209 /** 3210 * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}. 3211 * 3212 * @param file the file to write 3213 * @param data the content to write to the file 3214 * @throws IOException in case of an I/O error 3215 * @since 2.0 3216 * @deprecated Use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding) 3217 */ 3218 @Deprecated 3219 public static void write(final File file, final CharSequence data) throws IOException { 3220 write(file, data, Charset.defaultCharset(), false); 3221 } 3222 3223 /** 3224 * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}. 3225 * 3226 * @param file the file to write 3227 * @param data the content to write to the file 3228 * @param append if {@code true}, then the data will be added to the end of the file rather than overwriting 3229 * @throws IOException in case of an I/O error 3230 * @since 2.1 3231 * @deprecated Use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding) 3232 */ 3233 @Deprecated 3234 public static void write(final File file, final CharSequence data, final boolean append) throws IOException { 3235 write(file, data, Charset.defaultCharset(), append); 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 name of the requested charset, {@code null} means platform default 3244 * @throws IOException in case of an I/O error 3245 * @since 2.3 3246 */ 3247 public static void write(final File file, final CharSequence data, final Charset charset) throws IOException { 3248 write(file, data, charset, false); 3249 } 3250 3251 /** 3252 * Writes a CharSequence to a file creating the file if it does not exist. 3253 * 3254 * @param file the file to write 3255 * @param data the content to write to the file 3256 * @param charset the charset to use, {@code null} means platform default 3257 * @param append if {@code true}, then the data will be added to the 3258 * end of the file rather than overwriting 3259 * @throws IOException in case of an I/O error 3260 * @since 2.3 3261 */ 3262 public static void write(final File file, final CharSequence data, final Charset charset, final boolean append) throws IOException { 3263 writeStringToFile(file, Objects.toString(data, null), charset, append); 3264 } 3265 3266 /** 3267 * Writes a CharSequence to a file creating the file if it does not exist. 3268 * 3269 * @param file the file to write 3270 * @param data the content to write to the file 3271 * @param charsetName the name of the requested charset, {@code null} means platform default 3272 * @throws IOException in case of an I/O error 3273 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3274 * @since 2.0 3275 */ 3276 public static void write(final File file, final CharSequence data, final String charsetName) throws IOException { 3277 write(file, data, charsetName, false); 3278 } 3279 3280 /** 3281 * Writes a CharSequence to a file creating the file if it does not exist. 3282 * 3283 * @param file the file to write 3284 * @param data the content to write to the file 3285 * @param charsetName the name of the requested charset, {@code null} means platform default 3286 * @param append if {@code true}, then the data will be added to the 3287 * end of the file rather than overwriting 3288 * @throws IOException in case of an I/O error 3289 * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM 3290 * @since 2.1 3291 */ 3292 public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) throws IOException { 3293 write(file, data, Charsets.toCharset(charsetName), append); 3294 } 3295 3296 // Must be called with a directory 3297 3298 /** 3299 * Writes a byte array to a file creating the file if it does not exist. 3300 * The parent directories of the file will be created if they do not exist. 3301 * 3302 * @param file the file to write to 3303 * @param data the content to write to the file 3304 * @throws IOException in case of an I/O error 3305 * @since 1.1 3306 */ 3307 public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException { 3308 writeByteArrayToFile(file, data, false); 3309 } 3310 3311 /** 3312 * Writes a byte array to a file creating the file if it does not exist. 3313 * 3314 * @param file the file to write to 3315 * @param data the content to write to the file 3316 * @param append if {@code true}, then bytes will be added to the 3317 * end of the file rather than overwriting 3318 * @throws IOException in case of an I/O error 3319 * @since 2.1 3320 */ 3321 public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException { 3322 writeByteArrayToFile(file, data, 0, data.length, append); 3323 } 3324 3325 /** 3326 * Writes {@code len} bytes from the specified byte array starting 3327 * at offset {@code off} to a file, creating the file if it does 3328 * not exist. 3329 * 3330 * @param file the file to write to 3331 * @param data the content to write to the file 3332 * @param off the start offset in the data 3333 * @param len the number of bytes to write 3334 * @throws IOException in case of an I/O error 3335 * @since 2.5 3336 */ 3337 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException { 3338 writeByteArrayToFile(file, data, off, len, false); 3339 } 3340 3341 /** 3342 * Writes {@code len} bytes from the specified byte array starting 3343 * at offset {@code off} to a file, creating the file if it does 3344 * not exist. 3345 * 3346 * @param file the file to write to 3347 * @param data the content to write to the file 3348 * @param off the start offset in the data 3349 * @param len the number of bytes to write 3350 * @param append if {@code true}, then bytes will be added to the 3351 * end of the file rather than overwriting 3352 * @throws IOException in case of an I/O error 3353 * @since 2.5 3354 */ 3355 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException { 3356 try (OutputStream out = newOutputStream(file, append)) { 3357 out.write(data, off, len); 3358 } 3359 } 3360 3361 /** 3362 * Writes the {@code toString()} value of each item in a collection to 3363 * the specified {@link File} line by line. 3364 * The default VM encoding and the default line ending will be used. 3365 * 3366 * @param file the file to write to 3367 * @param lines the lines to write, {@code null} entries produce blank lines 3368 * @throws IOException in case of an I/O error 3369 * @since 1.3 3370 */ 3371 public static void writeLines(final File file, final Collection<?> lines) throws IOException { 3372 writeLines(file, null, lines, null, false); 3373 } 3374 3375 /** 3376 * Writes the {@code toString()} value of each item in a collection to 3377 * the specified {@link File} line by line. 3378 * The default VM encoding and the default line ending will be used. 3379 * 3380 * @param file the file to write to 3381 * @param lines the lines to write, {@code null} entries produce blank lines 3382 * @param append if {@code true}, then the lines will be added to the 3383 * end of the file rather than overwriting 3384 * @throws IOException in case of an I/O error 3385 * @since 2.1 3386 */ 3387 public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException { 3388 writeLines(file, null, lines, null, append); 3389 } 3390 3391 /** 3392 * Writes the {@code toString()} value of each item in a collection to 3393 * the specified {@link File} line by line. 3394 * The default VM encoding and the specified line ending will be used. 3395 * 3396 * @param file the file to write to 3397 * @param lines the lines to write, {@code null} entries produce blank lines 3398 * @param lineEnding the line separator to use, {@code null} is system default 3399 * @throws IOException in case of an I/O error 3400 * @since 1.3 3401 */ 3402 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException { 3403 writeLines(file, null, lines, lineEnding, false); 3404 } 3405 3406 /** 3407 * Writes the {@code toString()} value of each item in a collection to 3408 * the specified {@link File} line by line. 3409 * The default VM encoding and the specified line ending will be used. 3410 * 3411 * @param file the file to write to 3412 * @param lines the lines to write, {@code null} entries produce blank lines 3413 * @param lineEnding the line separator to use, {@code null} is system default 3414 * @param append if {@code true}, then the lines will be added to the 3415 * end of the file rather than overwriting 3416 * @throws IOException in case of an I/O error 3417 * @since 2.1 3418 */ 3419 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException { 3420 writeLines(file, null, lines, lineEnding, append); 3421 } 3422 3423 /** 3424 * Writes the {@code toString()} value of each item in a collection to 3425 * the specified {@link File} line by line. 3426 * The specified character encoding and the default line ending will be used. 3427 * The parent directories of the file will be created if they do not exist. 3428 * 3429 * @param file the file to write to 3430 * @param charsetName the name of the requested charset, {@code null} means platform default 3431 * @param lines the lines to write, {@code null} entries produce blank lines 3432 * @throws IOException in case of an I/O error 3433 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3434 * @since 1.1 3435 */ 3436 public static void writeLines(final File file, final String charsetName, final Collection<?> lines) throws IOException { 3437 writeLines(file, charsetName, lines, null, false); 3438 } 3439 3440 /** 3441 * Writes the {@code toString()} value of each item in a collection to 3442 * the specified {@link File} line by line, optionally appending. 3443 * The specified character encoding and the default line ending will be used. 3444 * 3445 * @param file the file to write to 3446 * @param charsetName the name of the requested charset, {@code null} means platform default 3447 * @param lines the lines to write, {@code null} entries produce blank lines 3448 * @param append if {@code true}, then the lines will be added to the 3449 * end of the file rather than overwriting 3450 * @throws IOException in case of an I/O error 3451 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3452 * @since 2.1 3453 */ 3454 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final boolean append) throws IOException { 3455 writeLines(file, charsetName, lines, null, append); 3456 } 3457 3458 /** 3459 * Writes the {@code toString()} value of each item in a collection to 3460 * the specified {@link File} line by line. 3461 * The specified character encoding and the line ending will be used. 3462 * The parent directories of the file will be created if they do not exist. 3463 * 3464 * @param file the file to write to 3465 * @param charsetName the name of the requested charset, {@code null} means platform default 3466 * @param lines the lines to write, {@code null} entries produce blank lines 3467 * @param lineEnding the line separator to use, {@code null} is system default 3468 * @throws IOException in case of an I/O error 3469 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3470 * @since 1.1 3471 */ 3472 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding) throws IOException { 3473 writeLines(file, charsetName, lines, lineEnding, false); 3474 } 3475 3476 /** 3477 * Writes the {@code toString()} value of each item in a collection to 3478 * the specified {@link File} line by line. 3479 * The specified character encoding and the line ending will be used. 3480 * 3481 * @param file the file to write to 3482 * @param charsetName the name of the requested charset, {@code null} means platform default 3483 * @param lines the lines to write, {@code null} entries produce blank lines 3484 * @param lineEnding the line separator to use, {@code null} is system default 3485 * @param append if {@code true}, then the lines will be added to the 3486 * end of the file rather than overwriting 3487 * @throws IOException in case of an I/O error 3488 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3489 * @since 2.1 3490 */ 3491 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding, final boolean append) 3492 throws IOException { 3493 try (OutputStream out = new BufferedOutputStream(newOutputStream(file, append))) { 3494 IOUtils.writeLines(lines, lineEnding, out, charsetName); 3495 } 3496 } 3497 3498 /** 3499 * Writes a String to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}. 3500 * 3501 * @param file the file to write 3502 * @param data the content to write to the file 3503 * @throws IOException in case of an I/O error 3504 * @deprecated Use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding) 3505 */ 3506 @Deprecated 3507 public static void writeStringToFile(final File file, final String data) throws IOException { 3508 writeStringToFile(file, data, Charset.defaultCharset(), false); 3509 } 3510 3511 /** 3512 * Writes a String to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}. 3513 * 3514 * @param file the file to write 3515 * @param data the content to write to the file 3516 * @param append if {@code true}, then the String will be added to the end of the file rather than overwriting 3517 * @throws IOException in case of an I/O error 3518 * @since 2.1 3519 * @deprecated Use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding) 3520 */ 3521 @Deprecated 3522 public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException { 3523 writeStringToFile(file, data, Charset.defaultCharset(), append); 3524 } 3525 3526 /** 3527 * Writes a String to a file creating the file if it does not exist. 3528 * The parent directories of the file will be created if they do not exist. 3529 * 3530 * @param file the file to write 3531 * @param data the content to write to the file 3532 * @param charset the charset to use, {@code null} means platform default 3533 * @throws IOException in case of an I/O error 3534 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3535 * @since 2.4 3536 */ 3537 public static void writeStringToFile(final File file, final String data, final Charset charset) throws IOException { 3538 writeStringToFile(file, data, charset, false); 3539 } 3540 3541 /** 3542 * Writes a String to a file, creating the file if it does not exist. 3543 * The parent directories of the file are created if they do not exist. 3544 * 3545 * @param file the file to write 3546 * @param data the content to write to the file 3547 * @param charset the charset to use, {@code null} means platform default 3548 * @param append if {@code true}, then the String will be added to the 3549 * end of the file rather than overwriting 3550 * @throws IOException in case of an I/O error 3551 * @since 2.3 3552 */ 3553 public static void writeStringToFile(final File file, final String data, final Charset charset, final boolean append) throws IOException { 3554 try (OutputStream out = newOutputStream(file, append)) { 3555 IOUtils.write(data, out, charset); 3556 } 3557 } 3558 3559 /** 3560 * Writes a String to a file, creating the file if it does not exist. 3561 * The parent directories of the file are created if they do not exist. 3562 * 3563 * @param file the file to write 3564 * @param data the content to write to the file 3565 * @param charsetName the name of the requested charset, {@code null} means platform default 3566 * @throws IOException in case of an I/O error 3567 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM 3568 */ 3569 public static void writeStringToFile(final File file, final String data, final String charsetName) throws IOException { 3570 writeStringToFile(file, data, charsetName, false); 3571 } 3572 3573 /** 3574 * Writes a String to a file, creating the file if it does not exist. 3575 * The parent directories of the file are created if they do not exist. 3576 * 3577 * @param file the file to write 3578 * @param data the content to write to the file 3579 * @param charsetName the name of the requested charset, {@code null} means platform default 3580 * @param append if {@code true}, then the String will be added to the 3581 * end of the file rather than overwriting 3582 * @throws IOException in case of an I/O error 3583 * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM 3584 * @since 2.1 3585 */ 3586 public static void writeStringToFile(final File file, final String data, final String charsetName, final boolean append) throws IOException { 3587 writeStringToFile(file, data, Charsets.toCharset(charsetName), append); 3588 } 3589 3590 /** 3591 * Instances should NOT be constructed in standard programming. 3592 * 3593 * @deprecated TODO Make private in 3.0. 3594 */ 3595 @Deprecated 3596 public FileUtils() { //NOSONAR 3597 // empty 3598 } 3599 3600}