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