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