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