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