FileUtils.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.io;

  18. import java.io.BufferedInputStream;
  19. import java.io.BufferedOutputStream;
  20. import java.io.File;
  21. import java.io.FileFilter;
  22. import java.io.FileInputStream;
  23. import java.io.FileNotFoundException;
  24. import java.io.FileOutputStream;
  25. import java.io.FilenameFilter;
  26. import java.io.IOException;
  27. import java.io.InputStream;
  28. import java.io.InputStreamReader;
  29. import java.io.OutputStream;
  30. import java.io.Reader;
  31. import java.io.UncheckedIOException;
  32. import java.math.BigInteger;
  33. import java.net.URL;
  34. import java.nio.ByteBuffer;
  35. import java.nio.charset.Charset;
  36. import java.nio.charset.StandardCharsets;
  37. import java.nio.charset.UnsupportedCharsetException;
  38. import java.nio.file.CopyOption;
  39. import java.nio.file.DirectoryStream;
  40. import java.nio.file.FileVisitOption;
  41. import java.nio.file.FileVisitResult;
  42. import java.nio.file.Files;
  43. import java.nio.file.LinkOption;
  44. import java.nio.file.NoSuchFileException;
  45. import java.nio.file.NotDirectoryException;
  46. import java.nio.file.Path;
  47. import java.nio.file.StandardCopyOption;
  48. import java.nio.file.attribute.BasicFileAttributeView;
  49. import java.nio.file.attribute.BasicFileAttributes;
  50. import java.nio.file.attribute.FileTime;
  51. import java.time.Duration;
  52. import java.time.Instant;
  53. import java.time.LocalTime;
  54. import java.time.OffsetDateTime;
  55. import java.time.OffsetTime;
  56. import java.time.ZoneId;
  57. import java.time.chrono.ChronoLocalDate;
  58. import java.time.chrono.ChronoLocalDateTime;
  59. import java.time.chrono.ChronoZonedDateTime;
  60. import java.util.ArrayList;
  61. import java.util.Arrays;
  62. import java.util.Collection;
  63. import java.util.Collections;
  64. import java.util.Date;
  65. import java.util.HashSet;
  66. import java.util.Iterator;
  67. import java.util.List;
  68. import java.util.Objects;
  69. import java.util.Set;
  70. import java.util.stream.Collectors;
  71. import java.util.stream.Stream;
  72. import java.util.zip.CRC32;
  73. import java.util.zip.CheckedInputStream;
  74. import java.util.zip.Checksum;

  75. import org.apache.commons.io.file.AccumulatorPathVisitor;
  76. import org.apache.commons.io.file.Counters;
  77. import org.apache.commons.io.file.PathFilter;
  78. import org.apache.commons.io.file.PathUtils;
  79. import org.apache.commons.io.file.StandardDeleteOption;
  80. import org.apache.commons.io.filefilter.FileEqualsFileFilter;
  81. import org.apache.commons.io.filefilter.FileFileFilter;
  82. import org.apache.commons.io.filefilter.IOFileFilter;
  83. import org.apache.commons.io.filefilter.SuffixFileFilter;
  84. import org.apache.commons.io.filefilter.TrueFileFilter;
  85. import org.apache.commons.io.function.IOConsumer;
  86. import org.apache.commons.io.function.Uncheck;

  87. /**
  88.  * General file manipulation utilities.
  89.  * <p>
  90.  * Facilities are provided in the following areas:
  91.  * </p>
  92.  * <ul>
  93.  * <li>writing to a file
  94.  * <li>reading from a file
  95.  * <li>make a directory including parent directories
  96.  * <li>copying files and directories
  97.  * <li>deleting files and directories
  98.  * <li>converting to and from a URL
  99.  * <li>listing files and directories by filter and extension
  100.  * <li>comparing file content
  101.  * <li>file last changed date
  102.  * <li>calculating a checksum
  103.  * </ul>
  104.  * <p>
  105.  * Note that a specific charset should be specified whenever possible. Relying on the platform default means that the
  106.  * code is Locale-dependent. Only use the default if the files are known to always use the platform default.
  107.  * </p>
  108.  * <p>
  109.  * {@link SecurityException} are not documented in the Javadoc.
  110.  * </p>
  111.  * <p>
  112.  * Provenance: Excalibur, Alexandria, Commons-Utils
  113.  * </p>
  114.  */
  115. public class FileUtils {

  116.     private static final String PROTOCOL_FILE = "file";

  117.     /**
  118.      * The number of bytes in a kilobyte.
  119.      */
  120.     public static final long ONE_KB = 1024;

  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.      * The number of bytes in a megabyte.
  129.      */
  130.     public static final long ONE_MB = ONE_KB * ONE_KB;

  131.     /**
  132.      * The number of bytes in a megabyte.
  133.      *
  134.      * @since 2.4
  135.      */
  136.     public static final BigInteger ONE_MB_BI = ONE_KB_BI.multiply(ONE_KB_BI);

  137.     /**
  138.      * The number of bytes in a gigabyte.
  139.      */
  140.     public static final long ONE_GB = ONE_KB * ONE_MB;

  141.     /**
  142.      * The number of bytes in a gigabyte.
  143.      *
  144.      * @since 2.4
  145.      */
  146.     public static final BigInteger ONE_GB_BI = ONE_KB_BI.multiply(ONE_MB_BI);

  147.     /**
  148.      * The number of bytes in a terabyte.
  149.      */
  150.     public static final long ONE_TB = ONE_KB * ONE_GB;

  151.     /**
  152.      * The number of bytes in a terabyte.
  153.      *
  154.      * @since 2.4
  155.      */
  156.     public static final BigInteger ONE_TB_BI = ONE_KB_BI.multiply(ONE_GB_BI);

  157.     /**
  158.      * The number of bytes in a petabyte.
  159.      */
  160.     public static final long ONE_PB = ONE_KB * ONE_TB;

  161.     /**
  162.      * The number of bytes in a petabyte.
  163.      *
  164.      * @since 2.4
  165.      */
  166.     public static final BigInteger ONE_PB_BI = ONE_KB_BI.multiply(ONE_TB_BI);

  167.     /**
  168.      * The number of bytes in an exabyte.
  169.      */
  170.     public static final long ONE_EB = ONE_KB * ONE_PB;

  171.     /**
  172.      * The number of bytes in an exabyte.
  173.      *
  174.      * @since 2.4
  175.      */
  176.     public static final BigInteger ONE_EB_BI = ONE_KB_BI.multiply(ONE_PB_BI);

  177.     /**
  178.      * The number of bytes in a zettabyte.
  179.      */
  180.     public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB));

  181.     /**
  182.      * The number of bytes in a yottabyte.
  183.      */
  184.     public static final BigInteger ONE_YB = ONE_KB_BI.multiply(ONE_ZB);

  185.     /**
  186.      * An empty array of type {@link File}.
  187.      */
  188.     public static final File[] EMPTY_FILE_ARRAY = {};

  189.     /**
  190.      * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
  191.      * <p>
  192.      * If the size is over 1GB, the size is returned as the number of whole GB, the size is rounded down to the
  193.      * nearest GB boundary.
  194.      * </p>
  195.      * <p>
  196.      * Similarly for the 1MB and 1KB boundaries.
  197.      * </p>
  198.      *
  199.      * @param size the number of bytes
  200.      * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
  201.      * @throws NullPointerException if the given {@link BigInteger} is {@code null}.
  202.      * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
  203.      * @since 2.4
  204.      */
  205.     // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
  206.     public static String byteCountToDisplaySize(final BigInteger size) {
  207.         Objects.requireNonNull(size, "size");
  208.         final String displaySize;

  209.         if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) {
  210.             displaySize = size.divide(ONE_EB_BI) + " EB";
  211.         } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) {
  212.             displaySize = size.divide(ONE_PB_BI) + " PB";
  213.         } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) {
  214.             displaySize = size.divide(ONE_TB_BI) + " TB";
  215.         } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) {
  216.             displaySize = size.divide(ONE_GB_BI) + " GB";
  217.         } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) {
  218.             displaySize = size.divide(ONE_MB_BI) + " MB";
  219.         } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) {
  220.             displaySize = size.divide(ONE_KB_BI) + " KB";
  221.         } else {
  222.             displaySize = size + " bytes";
  223.         }
  224.         return displaySize;
  225.     }

  226.     /**
  227.      * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
  228.      * <p>
  229.      * If the size is over 1GB, the size is returned as the number of whole GB, the size is rounded down to the
  230.      * nearest GB boundary.
  231.      * </p>
  232.      * <p>
  233.      * Similarly for the 1MB and 1KB boundaries.
  234.      * </p>
  235.      *
  236.      * @param size the number of bytes
  237.      * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
  238.      * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
  239.      */
  240.     // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
  241.     public static String byteCountToDisplaySize(final long size) {
  242.         return byteCountToDisplaySize(BigInteger.valueOf(size));
  243.     }

  244.     /**
  245.      * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
  246.      * <p>
  247.      * If the size is over 1GB, the size is returned as the number of whole GB, the size is rounded down to the
  248.      * nearest GB boundary.
  249.      * </p>
  250.      * <p>
  251.      * Similarly for the 1MB and 1KB boundaries.
  252.      * </p>
  253.      *
  254.      * @param size the number of bytes
  255.      * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
  256.      * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
  257.      * @since 2.12.0
  258.      */
  259.     // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
  260.     public static String byteCountToDisplaySize(final Number size) {
  261.         return byteCountToDisplaySize(size.longValue());
  262.     }

  263.     /**
  264.      * Requires that the given {@link File} is non-null and exists (if strict is true).
  265.      *
  266.      * @param file The {@link File} to check.
  267.      * @param strict whether to check that the {@code file} exists.
  268.      * @throws FileNotFoundException if the file does not exist.
  269.      * @throws NullPointerException  if the given {@link File} is {@code null}.
  270.      */
  271.     private static void checkExists(final File file, final boolean strict) throws FileNotFoundException {
  272.         Objects.requireNonNull(file, PROTOCOL_FILE);
  273.         if (strict && !file.exists()) {
  274.             throw new FileNotFoundException(file.toString());
  275.         }
  276.     }

  277.     /**
  278.      * Requires that the given {@link File} exists, and throws a {@link FileNotFoundException} if it doesn't.
  279.      *
  280.      * @param file The {@link File} to check.
  281.      * @param name The NullPointerException message.
  282.      * @throws FileNotFoundException if the file does not exist.
  283.      * @throws NullPointerException  if the given {@link File} is {@code null}.
  284.      */
  285.     private static void checkFileExists(final File file, final String name) throws FileNotFoundException {
  286.         Objects.requireNonNull(file, name);
  287.         if (!file.isFile()) {
  288.             if (file.exists()) {
  289.                 throw new IllegalArgumentException("Parameter '" + name + "' is not a file: " + file);
  290.             }
  291.             if (!Files.isSymbolicLink(file.toPath())) {
  292.                 throw new FileNotFoundException("Source '" + file + "' does not exist");
  293.             }
  294.         }
  295.     }

  296.     private static File checkIsFile(final File file, final String name) {
  297.         if (file.isFile()) {
  298.             return file;
  299.         }
  300.         throw new IllegalArgumentException(String.format("Parameter '%s' is not a file: %s", name, file));
  301.     }

  302.     /**
  303.      * Computes the checksum of a file using the specified checksum object. Multiple files may be checked using one
  304.      * {@link Checksum} instance if desired simply by reusing the same checksum object. For example:
  305.      *
  306.      * <pre>
  307.      * long checksum = FileUtils.checksum(file, new CRC32()).getValue();
  308.      * </pre>
  309.      *
  310.      * @param file the file to checksum, must not be {@code null}
  311.      * @param checksum the checksum object to be used, must not be {@code null}
  312.      * @return the checksum specified, updated with the content of the file
  313.      * @throws NullPointerException if the given {@link File} is {@code null}.
  314.      * @throws NullPointerException if the given {@link Checksum} is {@code null}.
  315.      * @throws IllegalArgumentException if the given {@link File} is not a file.
  316.      * @throws FileNotFoundException if the file does not exist
  317.      * @throws IOException if an IO error occurs reading the file.
  318.      * @since 1.3
  319.      */
  320.     public static Checksum checksum(final File file, final Checksum checksum) throws IOException {
  321.         checkFileExists(file, PROTOCOL_FILE);
  322.         Objects.requireNonNull(checksum, "checksum");
  323.         try (InputStream inputStream = new CheckedInputStream(Files.newInputStream(file.toPath()), checksum)) {
  324.             IOUtils.consume(inputStream);
  325.         }
  326.         return checksum;
  327.     }

  328.     /**
  329.      * Computes the checksum of a file using the CRC32 checksum routine.
  330.      * The value of the checksum is returned.
  331.      *
  332.      * @param file the file to checksum, must not be {@code null}
  333.      * @return the checksum value
  334.      * @throws NullPointerException if the {@code file} is {@code null}.
  335.      * @throws IllegalArgumentException if the {@code file} does not exist or is not a file.
  336.      * @throws IOException              if an IO error occurs reading the file.
  337.      * @since 1.3
  338.      */
  339.     public static long checksumCRC32(final File file) throws IOException {
  340.         return checksum(file, new CRC32()).getValue();
  341.     }

  342.     /**
  343.      * Cleans a directory without deleting it.
  344.      *
  345.      * @param directory directory to clean
  346.      * @throws NullPointerException if the given {@link File} is {@code null}.
  347.      * @throws IllegalArgumentException if the {@code directory} does not exist or is not a directory.
  348.      * @throws IOException if an I/O error occurs.
  349.      * @see #forceDelete(File)
  350.      */
  351.     public static void cleanDirectory(final File directory) throws IOException {
  352.         IOConsumer.forAll(f -> forceDelete(f, false), listFiles(directory, null));
  353.     }

  354.     /**
  355.      * Cleans a directory without deleting it.
  356.      *
  357.      * @param directory directory to clean, must not be {@code null}
  358.      * @throws NullPointerException if the given {@link File} is {@code null}.
  359.      * @throws IllegalArgumentException if the {@code directory} does not exist or is not a directory.
  360.      * @throws IOException if an I/O error occurs.
  361.      * @see #forceDeleteOnExit(File)
  362.      */
  363.     private static void cleanDirectoryOnExit(final File directory) throws IOException {
  364.         IOConsumer.forAll(FileUtils::forceDeleteOnExit, listFiles(directory, null));
  365.     }

  366.     /**
  367.      * Tests whether the contents of two files are equal.
  368.      * <p>
  369.      * This method checks to see if the two files are different lengths or if they point to the same file, before
  370.      * resorting to byte-by-byte comparison of the contents.
  371.      * </p>
  372.      *
  373.      * @param file1 the first file
  374.      * @param file2 the second file
  375.      * @return true if the content of the files are equal or they both don't exist, false otherwise
  376.      * @throws IllegalArgumentException when an input is not a file.
  377.      * @throws IOException If an I/O error occurs.
  378.      * @see PathUtils#fileContentEquals(Path,Path)
  379.      */
  380.     public static boolean contentEquals(final File file1, final File file2) throws IOException {
  381.         if (file1 == null && file2 == null) {
  382.             return true;
  383.         }
  384.         if (file1 == null || file2 == null) {
  385.             return false;
  386.         }
  387.         final boolean file1Exists = file1.exists();
  388.         if (file1Exists != file2.exists()) {
  389.             return false;
  390.         }

  391.         if (!file1Exists) {
  392.             // two not existing files are equal
  393.             return true;
  394.         }

  395.         checkIsFile(file1, "file1");
  396.         checkIsFile(file2, "file2");

  397.         if (file1.length() != file2.length()) {
  398.             // lengths differ, cannot be equal
  399.             return false;
  400.         }

  401.         if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
  402.             // same file
  403.             return true;
  404.         }

  405.         return PathUtils.fileContentEquals(file1.toPath(), file2.toPath());
  406.     }

  407.     /**
  408.      * Compares the contents of two files to determine if they are equal or not.
  409.      * <p>
  410.      * This method checks to see if the two files point to the same file,
  411.      * before resorting to line-by-line comparison of the contents.
  412.      * </p>
  413.      *
  414.      * @param file1       the first file
  415.      * @param file2       the second file
  416.      * @param charsetName the name of the requested charset.
  417.      *                    May be null, in which case the platform default is used
  418.      * @return true if the content of the files are equal or neither exists,
  419.      * false otherwise
  420.      * @throws IllegalArgumentException when an input is not a file.
  421.      * @throws IOException in case of an I/O error.
  422.      * @throws UnsupportedCharsetException If the named charset is unavailable (unchecked exception).
  423.      * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader)
  424.      * @since 2.2
  425.      */
  426.     public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName)
  427.             throws IOException {
  428.         if (file1 == null && file2 == null) {
  429.             return true;
  430.         }
  431.         if (file1 == null || file2 == null) {
  432.             return false;
  433.         }
  434.         final boolean file1Exists = file1.exists();
  435.         if (file1Exists != file2.exists()) {
  436.             return false;
  437.         }

  438.         if (!file1Exists) {
  439.             // two not existing files are equal
  440.             return true;
  441.         }

  442.         checkFileExists(file1, "file1");
  443.         checkFileExists(file2, "file2");

  444.         if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
  445.             // same file
  446.             return true;
  447.         }

  448.         final Charset charset = Charsets.toCharset(charsetName);
  449.         try (Reader input1 = new InputStreamReader(Files.newInputStream(file1.toPath()), charset);
  450.              Reader input2 = new InputStreamReader(Files.newInputStream(file2.toPath()), charset)) {
  451.             return IOUtils.contentEqualsIgnoreEOL(input1, input2);
  452.         }
  453.     }

  454.     /**
  455.      * Converts a Collection containing {@link File} instances into array
  456.      * representation. This is to account for the difference between
  457.      * File.listFiles() and FileUtils.listFiles().
  458.      *
  459.      * @param files a Collection containing {@link File} instances
  460.      * @return an array of {@link File}
  461.      */
  462.     public static File[] convertFileCollectionToFileArray(final Collection<File> files) {
  463.         return files.toArray(EMPTY_FILE_ARRAY);
  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. That is, copying /home/bar to /tmp/bang
  470.      * copies the contents of /home/bar into /tmp/bang. It does not create /tmp/bang/bar.
  471.      * </p>
  472.      * <p>
  473.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  474.      * method merges the source with the destination, with the source taking precedence.
  475.      * </p>
  476.      * <p>
  477.      * <strong>Note:</strong> This method tries to preserve the file's last
  478.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However it is
  479.      * not guaranteed that the operation will succeed. If the modification operation fails, it falls back to
  480.      * {@link File#setLastModified(long)}. If that fails, the method throws IOException.
  481.      * </p>
  482.      * <p>
  483.      * Symbolic links in the source directory are copied to new symbolic links in the destination
  484.      * directory that point to the original target. The target of the link is not copied unless
  485.      * it is also under the source directory. Even if it is under the source directory, the new symbolic
  486.      * link in the destination points to the original target in the source directory, not to the
  487.      * newly created copy of the target.
  488.      * </p>
  489.      *
  490.      * @param srcDir an existing directory to copy, must not be {@code null}.
  491.      * @param destDir the new directory, must not be {@code null}.
  492.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  493.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory,
  494.      *     the source and the destination directory are the same
  495.      * @throws FileNotFoundException if the source does not exist.
  496.      * @throws IOException if an error occurs, the destination is not writable, or setting the last-modified time didn't succeed
  497.      * @since 1.1
  498.      */
  499.     public static void copyDirectory(final File srcDir, final File destDir) throws IOException {
  500.         copyDirectory(srcDir, destDir, true);
  501.     }

  502.     /**
  503.      * Copies a whole directory to a new location.
  504.      * <p>
  505.      * This method copies the contents of the specified source directory to within the specified destination directory.
  506.      * </p>
  507.      * <p>
  508.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  509.      * method merges the source with the destination, with the source taking precedence.
  510.      * </p>
  511.      * <p>
  512.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last
  513.      * modified date/times using {@link File#setLastModified(long)}. However it is not guaranteed that those operations
  514.      * will succeed. If the modification operation fails, the method throws IOException.
  515.      * </p>
  516.      *
  517.      * @param srcDir an existing directory to copy, must not be {@code null}.
  518.      * @param destDir the new directory, must not be {@code null}.
  519.      * @param preserveFileDate true if the file date of the copy should be the same as the original.
  520.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory, or
  521.      *     the source and the destination directory are the same
  522.      * @throws FileNotFoundException if the source does not exist.
  523.      * @throws IOException if an error occurs, the destination is not writable, or setting the last-modified time didn't succeed
  524.      * @since 1.1
  525.      */
  526.     public static void copyDirectory(final File srcDir, final File destDir, final boolean preserveFileDate)
  527.         throws IOException {
  528.         copyDirectory(srcDir, destDir, null, preserveFileDate);
  529.     }

  530.     /**
  531.      * Copies a filtered directory to a new location preserving the file dates.
  532.      * <p>
  533.      * This method copies the contents of the specified source directory to within the specified destination directory.
  534.      * </p>
  535.      * <p>
  536.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  537.      * method merges the source with the destination, with the source taking precedence.
  538.      * </p>
  539.      * <p>
  540.      * <strong>Note:</strong> This method tries to preserve the files' last modified date/times using
  541.      * {@link File#setLastModified(long)}. However it is not guaranteed that those operations will succeed. If the
  542.      * modification operation fails, the method throws IOException.
  543.      * </p>
  544.      * <strong>Example: Copy directories only</strong>
  545.      *
  546.      * <pre>
  547.      * // only copy the directory structure
  548.      * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
  549.      * </pre>
  550.      *
  551.      * <strong>Example: Copy directories and txt files</strong>
  552.      *
  553.      * <pre>
  554.      * // Create a filter for ".txt" files
  555.      * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
  556.      * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.INSTANCE, txtSuffixFilter);
  557.      *
  558.      * // Create a filter for either directories or ".txt" files
  559.      * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
  560.      *
  561.      * // Copy using the filter
  562.      * FileUtils.copyDirectory(srcDir, destDir, filter);
  563.      * </pre>
  564.      *
  565.      * @param srcDir an existing directory to copy, must not be {@code null}.
  566.      * @param destDir the new directory, must not be {@code null}.
  567.      * @param filter the filter to apply, null means copy all directories and files should be the same as the original.
  568.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  569.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory, or
  570.      *     the source and the destination directory are the same
  571.      * @throws FileNotFoundException if the source does not exist.
  572.      * @throws IOException if an error occurs, the destination is not writable, or setting the last-modified time didn't succeed
  573.      * @since 1.4
  574.      */
  575.     public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter)
  576.         throws IOException {
  577.         copyDirectory(srcDir, destDir, filter, true);
  578.     }

  579.     /**
  580.      * Copies a filtered directory to a new location.
  581.      * <p>
  582.      * This method copies the contents of the specified source directory to within the specified destination directory.
  583.      * </p>
  584.      * <p>
  585.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  586.      * method merges the source with the destination, with the source taking precedence.
  587.      * </p>
  588.      * <p>
  589.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  590.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  591.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  592.      * {@link File#setLastModified(long)}. If that fails, the method throws IOException.
  593.      * </p>
  594.      * <strong>Example: Copy directories only</strong>
  595.      *
  596.      * <pre>
  597.      * // only copy the directory structure
  598.      * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
  599.      * </pre>
  600.      *
  601.      * <strong>Example: Copy directories and txt files</strong>
  602.      *
  603.      * <pre>
  604.      * // Create a filter for ".txt" files
  605.      * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
  606.      * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.INSTANCE, txtSuffixFilter);
  607.      *
  608.      * // Create a filter for either directories or ".txt" files
  609.      * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
  610.      *
  611.      * // Copy using the filter
  612.      * FileUtils.copyDirectory(srcDir, destDir, filter, false);
  613.      * </pre>
  614.      *
  615.      * @param srcDir an existing directory to copy, must not be {@code null}.
  616.      * @param destDir the new directory, must not be {@code null}.
  617.      * @param filter the filter to apply, null means copy all directories and files.
  618.      * @param preserveFileDate true if the file date of the copy should be the same as the original.
  619.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  620.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory,
  621.      *     the source and the destination directory are the same, or the destination is not writable
  622.      * @throws FileNotFoundException if the source does not exist.
  623.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  624.      * @since 1.4
  625.      */
  626.     public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate) throws IOException {
  627.         copyDirectory(srcDir, destDir, filter, preserveFileDate, StandardCopyOption.REPLACE_EXISTING, LinkOption.NOFOLLOW_LINKS);
  628.     }

  629.     /**
  630.      * Copies a filtered directory to a new location.
  631.      * <p>
  632.      * This method copies the contents of the specified source directory to within the specified destination directory.
  633.      * </p>
  634.      * <p>
  635.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  636.      * method merges the source with the destination, with the source taking precedence.
  637.      * </p>
  638.      * <p>
  639.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  640.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  641.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  642.      * {@link File#setLastModified(long)}. If that fails, the method throws IOException.
  643.      * </p>
  644.      * <strong>Example: Copy directories only</strong>
  645.      *
  646.      * <pre>
  647.      * // only copy the directory structure
  648.      * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
  649.      * </pre>
  650.      *
  651.      * <strong>Example: Copy directories and txt files</strong>
  652.      *
  653.      * <pre>
  654.      * // Create a filter for ".txt" files
  655.      * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
  656.      * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.INSTANCE, txtSuffixFilter);
  657.      *
  658.      * // Create a filter for either directories or ".txt" files
  659.      * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
  660.      *
  661.      * // Copy using the filter
  662.      * FileUtils.copyDirectory(srcDir, destDir, filter, false);
  663.      * </pre>
  664.      *
  665.      * @param srcDir an existing directory to copy, must not be {@code null}
  666.      * @param destDir the new directory, must not be {@code null}
  667.      * @param fileFilter the filter to apply, null means copy all directories and files
  668.      * @param preserveFileDate true if the file date of the copy should be the same as the original
  669.      * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.
  670.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  671.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory, or
  672.      *     the source and the destination directory are the same
  673.      * @throws FileNotFoundException if the source does not exist.
  674.      * @throws IOException if an error occurs, the destination is not writable, or setting the last-modified time didn't succeed
  675.      * @since 2.8.0
  676.      */
  677.     public static void copyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final boolean preserveFileDate,
  678.         final CopyOption... copyOptions) throws IOException {
  679.         Objects.requireNonNull(destDir, "destination");
  680.         requireDirectoryExists(srcDir, "srcDir");
  681.         requireCanonicalPathsNotEquals(srcDir, destDir);

  682.         // Cater for destination being directory within the source directory (see IO-141)
  683.         List<String> exclusionList = null;
  684.         final String srcDirCanonicalPath = srcDir.getCanonicalPath();
  685.         final String destDirCanonicalPath = destDir.getCanonicalPath();
  686.         if (destDirCanonicalPath.startsWith(srcDirCanonicalPath)) {
  687.             final File[] srcFiles = listFiles(srcDir, fileFilter);
  688.             if (srcFiles.length > 0) {
  689.                 exclusionList = new ArrayList<>(srcFiles.length);
  690.                 for (final File srcFile : srcFiles) {
  691.                     exclusionList.add(new File(destDir, srcFile.getName()).getCanonicalPath());
  692.                 }
  693.             }
  694.         }
  695.         doCopyDirectory(srcDir, destDir, fileFilter, exclusionList, preserveFileDate, copyOptions);
  696.     }

  697.     /**
  698.      * Copies a directory to within another directory preserving the file dates.
  699.      * <p>
  700.      * This method copies the source directory and all its contents to a directory of the same name in the specified
  701.      * destination directory.
  702.      * </p>
  703.      * <p>
  704.      * The destination directory is created if it does not exist. If the destination directory does exist, then this
  705.      * method merges the source with the destination, with the source taking precedence.
  706.      * </p>
  707.      * <p>
  708.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  709.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  710.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  711.      * {@link File#setLastModified(long)} and if that fails, the method throws IOException.
  712.      * </p>
  713.      *
  714.      * @param sourceDir an existing directory to copy, must not be {@code null}.
  715.      * @param destinationDir the directory to place the copy in, must not be {@code null}.
  716.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  717.      * @throws IllegalArgumentException if the source or destination is invalid.
  718.      * @throws FileNotFoundException if the source does not exist.
  719.      * @throws IOException if an error occurs, the destination is not writable, or setting the last-modified time didn't succeed
  720.      * @since 1.2
  721.      */
  722.     public static void copyDirectoryToDirectory(final File sourceDir, final File destinationDir) throws IOException {
  723.         Objects.requireNonNull(sourceDir, "sourceDir");
  724.         requireDirectoryIfExists(destinationDir, "destinationDir");
  725.         copyDirectory(sourceDir, new File(destinationDir, sourceDir.getName()), true);
  726.     }

  727.     /**
  728.      * Copies a file to a new location preserving the file date.
  729.      * <p>
  730.      * This method copies the contents of the specified source file to the specified destination file. The directory
  731.      * holding the destination file is created if it does not exist. If the destination file exists, then this method
  732.      * overwrites it. A symbolic link is resolved before copying so the new file is not a link.
  733.      * </p>
  734.      * <p>
  735.      * <strong>Note:</strong> This method tries to preserve the file's last modified date/times using
  736.      * {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is not guaranteed that the
  737.      * operation will succeed. If the modification operation fails, it falls back to
  738.      * {@link File#setLastModified(long)}, and if that fails, the method throws IOException.
  739.      * </p>
  740.      *
  741.      * @param srcFile an existing file to copy, must not be {@code null}.
  742.      * @param destFile the new file, must not be {@code null}.
  743.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  744.      * @throws IOException if source or destination is invalid.
  745.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  746.      * @throws IOException if the output file length is not the same as the input file length after the copy completes.
  747.      * @see #copyFileToDirectory(File, File)
  748.      * @see #copyFile(File, File, boolean)
  749.      */
  750.     public static void copyFile(final File srcFile, final File destFile) throws IOException {
  751.         copyFile(srcFile, destFile, StandardCopyOption.REPLACE_EXISTING);
  752.     }

  753.     /**
  754.      * Copies an existing file to a new file location.
  755.      * <p>
  756.      * This method copies the contents of the specified source file to the specified destination file. The directory
  757.      * holding the destination file is created if it does not exist. If the destination file exists, then this method
  758.      * overwrites it. A symbolic link is resolved before copying so the new file is not a link.
  759.      * </p>
  760.      * <p>
  761.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  762.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  763.      * not guaranteed that the operation will succeed. If the modification operation fails, it falls back to
  764.      * {@link File#setLastModified(long)}, and if that fails, the method throws IOException.
  765.      * </p>
  766.      *
  767.      * @param srcFile an existing file to copy, must not be {@code null}.
  768.      * @param destFile the new file, must not be {@code null}.
  769.      * @param preserveFileDate true if the file date of the copy should be the same as the original.
  770.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  771.      * @throws IOException if source or destination is invalid.
  772.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  773.      * @throws IOException if the output file length is not the same as the input file length after the copy completes
  774.      * @see #copyFile(File, File, boolean, CopyOption...)
  775.      */
  776.     public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException {
  777.         copyFile(srcFile, destFile, preserveFileDate, StandardCopyOption.REPLACE_EXISTING);
  778.     }

  779.     /**
  780.      * Copies the contents of a file to a new location.
  781.      * <p>
  782.      * This method copies the contents of the specified source file to the specified destination file. The directory
  783.      * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite
  784.      * it with {@link StandardCopyOption#REPLACE_EXISTING}.
  785.      * </p>
  786.      *
  787.      * <p>
  788.      * By default, a symbolic link is resolved before copying so the new file is not a link.
  789.      * To copy symbolic links as links, you can pass {@code LinkOption.NO_FOLLOW_LINKS} as the last argument.
  790.      * </p>
  791.      *
  792.      * <p>
  793.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  794.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  795.      * not guaranteed that the operation will succeed. If the modification operation fails, it falls back to
  796.      * {@link File#setLastModified(long)}, and if that fails, the method throws IOException.
  797.      * </p>
  798.      *
  799.      * @param srcFile an existing file to copy, must not be {@code null}.
  800.      * @param destFile the new file, must not be {@code null}.
  801.      * @param preserveFileDate true if the file date of the copy should be the same as the original.
  802.      * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.
  803.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  804.      * @throws FileNotFoundException if the source does not exist.
  805.      * @throws IllegalArgumentException if {@code srcFile} or {@code destFile} is not a file
  806.      * @throws IOException if the output file length is not the same as the input file length after the copy completes.
  807.      * @throws IOException if an I/O error occurs, setting the last-modified time didn't succeed,
  808.      *     or the destination is not writable
  809.      * @see #copyFileToDirectory(File, File, boolean)
  810.      * @since 2.8.0
  811.      */
  812.     public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException {
  813.         Objects.requireNonNull(destFile, "destination");
  814.         checkFileExists(srcFile, "srcFile");
  815.         requireCanonicalPathsNotEquals(srcFile, destFile);
  816.         createParentDirectories(destFile);
  817.         if (destFile.exists()) {
  818.             checkFileExists(destFile, "destFile");
  819.         }

  820.         final Path srcPath = srcFile.toPath();

  821.         Files.copy(srcPath, destFile.toPath(), copyOptions);

  822.         // On Windows, the last modified time is copied by default.
  823.         if (preserveFileDate && !Files.isSymbolicLink(srcPath) && !setTimes(srcFile, destFile)) {
  824.             throw new IOException("Cannot set the file time.");
  825.         }
  826.     }

  827.     /**
  828.      * Copies a file to a new location.
  829.      * <p>
  830.      * This method copies the contents of the specified source file to the specified destination file. The directory
  831.      * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite
  832.      * it if you use {@link StandardCopyOption#REPLACE_EXISTING}.
  833.      * </p>
  834.      *
  835.      * @param srcFile an existing file to copy, must not be {@code null}.
  836.      * @param destFile the new file, must not be {@code null}.
  837.      * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.
  838.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  839.      * @throws FileNotFoundException if the source does not exist.
  840.      * @throws IllegalArgumentException if source is not a file.
  841.      * @throws IOException if an I/O error occurs.
  842.      * @see StandardCopyOption
  843.      * @since 2.9.0
  844.      */
  845.     public static void copyFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException {
  846.         copyFile(srcFile, destFile, true, copyOptions);
  847.     }

  848.     /**
  849.      * Copies bytes from a {@link File} to an {@link OutputStream}.
  850.      * <p>
  851.      * This method buffers the input internally, so there is no need to use a {@link BufferedInputStream}.
  852.      * </p>
  853.      *
  854.      * @param input  the {@link File} to read.
  855.      * @param output the {@link OutputStream} to write.
  856.      * @return the number of bytes copied
  857.      * @throws NullPointerException if the File is {@code null}.
  858.      * @throws NullPointerException if the OutputStream is {@code null}.
  859.      * @throws IOException          if an I/O error occurs.
  860.      * @since 2.1
  861.      */
  862.     public static long copyFile(final File input, final OutputStream output) throws IOException {
  863.         try (InputStream fis = Files.newInputStream(input.toPath())) {
  864.             return IOUtils.copyLarge(fis, output);
  865.         }
  866.     }

  867.     /**
  868.      * Copies a file to a directory preserving the file date.
  869.      * <p>
  870.      * This method copies the contents of the specified source file to a file of the same name in the specified
  871.      * destination directory. The destination directory is created if it does not exist. If the destination file exists,
  872.      * then this method will overwrite it.
  873.      * </p>
  874.      * <p>
  875.      * <strong>Note:</strong> This method tries to preserve the file's last modified date/times using
  876.      * {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is not guaranteed that the
  877.      * operation will succeed. If the modification operation fails it falls back to
  878.      * {@link File#setLastModified(long)} and if that fails, the method throws IOException.
  879.      * </p>
  880.      *
  881.      * @param srcFile an existing file to copy, must not be {@code null}.
  882.      * @param destDir the directory to place the copy in, must not be {@code null}.
  883.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  884.      * @throws IllegalArgumentException if source or destination is invalid.
  885.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  886.      * @see #copyFile(File, File, boolean)
  887.      */
  888.     public static void copyFileToDirectory(final File srcFile, final File destDir) throws IOException {
  889.         copyFileToDirectory(srcFile, destDir, true);
  890.     }

  891.     /**
  892.      * Copies a file to a directory optionally preserving the file date.
  893.      * <p>
  894.      * This method copies the contents of the specified source file to a file of the same name in the specified
  895.      * destination directory. The destination directory is created if it does not exist. If the destination file exists,
  896.      * then this method will overwrite it.
  897.      * </p>
  898.      * <p>
  899.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  900.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  901.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  902.      * {@link File#setLastModified(long)} and if that fails, the method throws IOException.
  903.      * </p>
  904.      *
  905.      * @param sourceFile an existing file to copy, must not be {@code null}.
  906.      * @param destinationDir the directory to place the copy in, must not be {@code null}.
  907.      * @param preserveFileDate true if the file date of the copy should be the same as the original.
  908.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  909.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  910.      * @throws IOException if the output file length is not the same as the input file length after the copy completes.
  911.      * @see #copyFile(File, File, CopyOption...)
  912.      * @since 1.3
  913.      */
  914.     public static void copyFileToDirectory(final File sourceFile, final File destinationDir, final boolean preserveFileDate) throws IOException {
  915.         Objects.requireNonNull(sourceFile, "sourceFile");
  916.         requireDirectoryIfExists(destinationDir, "destinationDir");
  917.         copyFile(sourceFile, new File(destinationDir, sourceFile.getName()), preserveFileDate);
  918.     }

  919.     /**
  920.      * Copies bytes from an {@link InputStream} {@code source} to a file
  921.      * {@code destination}. The directories up to {@code destination}
  922.      * will be created if they don't already exist. {@code destination}
  923.      * will be overwritten if it already exists.
  924.      * <p>
  925.      * <em>The {@code source} stream is closed.</em>
  926.      * </p>
  927.      * <p>
  928.      * See {@link #copyToFile(InputStream, File)} for a method that does not close the input stream.
  929.      * </p>
  930.      *
  931.      * @param source      the {@link InputStream} to copy bytes from, must not be {@code null}, will be closed
  932.      * @param destination the non-directory {@link File} to write bytes to
  933.      *                    (possibly overwriting), must not be {@code null}
  934.      * @throws IOException if {@code destination} is a directory
  935.      * @throws IOException if {@code destination} cannot be written
  936.      * @throws IOException if {@code destination} needs creating but can't be
  937.      * @throws IOException if an IO error occurs during copying
  938.      * @since 2.0
  939.      */
  940.     public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException {
  941.         try (InputStream inputStream = source) {
  942.             copyToFile(inputStream, destination);
  943.         }
  944.     }

  945.     /**
  946.      * Copies a file or directory to within another directory preserving the file dates.
  947.      * <p>
  948.      * This method copies the source file or directory, along with all its contents, to a directory of the same name in the
  949.      * specified destination directory.
  950.      * </p>
  951.      * <p>
  952.      * The destination directory is created if it does not exist. If the destination directory does exist, then this method
  953.      * merges the source with the destination, with the source taking precedence.
  954.      * </p>
  955.      * <p>
  956.      * <strong>Note:</strong> Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last
  957.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  958.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  959.      * {@link File#setLastModified(long)} and if that fails, the method throws IOException.
  960.      * </p>
  961.      *
  962.      * @param sourceFile an existing file or directory to copy, must not be {@code null}.
  963.      * @param destinationDir the directory to place the copy in, must not be {@code null}.
  964.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  965.      * @throws IllegalArgumentException if the source or destination is invalid.
  966.      * @throws FileNotFoundException if the source does not exist.
  967.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  968.      * @see #copyDirectoryToDirectory(File, File)
  969.      * @see #copyFileToDirectory(File, File)
  970.      * @since 2.6
  971.      */
  972.     public static void copyToDirectory(final File sourceFile, final File destinationDir) throws IOException {
  973.         Objects.requireNonNull(sourceFile, "sourceFile");
  974.         if (sourceFile.isFile()) {
  975.             copyFileToDirectory(sourceFile, destinationDir);
  976.         } else if (sourceFile.isDirectory()) {
  977.             copyDirectoryToDirectory(sourceFile, destinationDir);
  978.         } else {
  979.             throw new FileNotFoundException("The source " + sourceFile + " does not exist");
  980.         }
  981.     }

  982.     /**
  983.      * Copies a files to a directory preserving each file's date.
  984.      * <p>
  985.      * This method copies the contents of the specified source files
  986.      * to a file of the same name in the specified destination directory.
  987.      * The destination directory is created if it does not exist.
  988.      * If the destination file exists, then this method will overwrite it.
  989.      * </p>
  990.      * <p>
  991.      * <strong>Note:</strong> This method tries to preserve the file's last
  992.      * modified date/times using {@link BasicFileAttributeView#setTimes(FileTime, FileTime, FileTime)}. However, it is
  993.      * not guaranteed that the operation will succeed. If the modification operation fails it falls back to
  994.      * {@link File#setLastModified(long)} and if that fails, the method throws IOException.
  995.      * </p>
  996.      *
  997.      * @param sourceIterable  existing files to copy, must not be {@code null}.
  998.      * @param destinationDir  the directory to place the copies in, must not be {@code null}.
  999.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  1000.      * @throws IOException if source or destination is invalid.
  1001.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  1002.      * @see #copyFileToDirectory(File, File)
  1003.      * @since 2.6
  1004.      */
  1005.     public static void copyToDirectory(final Iterable<File> sourceIterable, final File destinationDir) throws IOException {
  1006.         Objects.requireNonNull(sourceIterable, "sourceIterable");
  1007.         for (final File src : sourceIterable) {
  1008.             copyFileToDirectory(src, destinationDir);
  1009.         }
  1010.     }

  1011.     /**
  1012.      * Copies bytes from an {@link InputStream} source to a {@link File} destination. The directories
  1013.      * up to {@code destination} will be created if they don't already exist. {@code destination} will be
  1014.      * overwritten if it already exists. The {@code source} stream is left open, e.g. for use with
  1015.      * {@link java.util.zip.ZipInputStream ZipInputStream}. See {@link #copyInputStreamToFile(InputStream, File)} for a
  1016.      * method that closes the input stream.
  1017.      *
  1018.      * @param inputStream the {@link InputStream} to copy bytes from, must not be {@code null}
  1019.      * @param file the non-directory {@link File} to write bytes to (possibly overwriting), must not be
  1020.      *        {@code null}
  1021.      * @throws NullPointerException if the InputStream is {@code null}.
  1022.      * @throws NullPointerException if the File is {@code null}.
  1023.      * @throws IllegalArgumentException if the file object is a directory.
  1024.      * @throws IllegalArgumentException if the file is not writable.
  1025.      * @throws IOException if the directories could not be created.
  1026.      * @throws IOException if an IO error occurs during copying.
  1027.      * @since 2.5
  1028.      */
  1029.     public static void copyToFile(final InputStream inputStream, final File file) throws IOException {
  1030.         try (OutputStream out = newOutputStream(file, false)) {
  1031.             IOUtils.copy(inputStream, out);
  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.      * Copies bytes from the URL {@code source} to a file {@code destination}. The directories up to
  1061.      * {@code destination} will be created if they don't already exist. {@code destination} will be
  1062.      * overwritten if it already exists.
  1063.      *
  1064.      * @param source the {@link URL} to copy bytes from, must not be {@code null}
  1065.      * @param destination the non-directory {@link File} to write bytes to (possibly overwriting), must not be
  1066.      *        {@code null}
  1067.      * @param connectionTimeoutMillis the number of milliseconds until this method will time out if no connection could
  1068.      *        be established to the {@code source}
  1069.      * @param readTimeoutMillis the number of milliseconds until this method will time out if no data could be read from
  1070.      *        the {@code source}
  1071.      * @throws IOException if {@code source} URL cannot be opened
  1072.      * @throws IOException if {@code destination} is a directory
  1073.      * @throws IOException if {@code destination} cannot be written
  1074.      * @throws IOException if {@code destination} needs creating but can't be
  1075.      * @throws IOException if an IO error occurs during copying
  1076.      * @since 2.0
  1077.      */
  1078.     public static void copyURLToFile(final URL source, final File destination, final int connectionTimeoutMillis, final int readTimeoutMillis)
  1079.         throws IOException {
  1080.         try (CloseableURLConnection urlConnection = CloseableURLConnection.open(source)) {
  1081.             urlConnection.setConnectTimeout(connectionTimeoutMillis);
  1082.             urlConnection.setReadTimeout(readTimeoutMillis);
  1083.             try (InputStream stream = urlConnection.getInputStream()) {
  1084.                 copyInputStreamToFile(stream, destination);
  1085.             }
  1086.         }
  1087.     }

  1088.     /**
  1089.      * Creates all parent directories for a File object, including any necessary but non-existent parent directories. If a parent directory already exists or
  1090.      * is null, nothing happens.
  1091.      *
  1092.      * @param file the File that may need parents, may be null.
  1093.      * @return The parent directory, or {@code null} if the given File does have a parent.
  1094.      * @throws IOException       if the directory was not created along with all its parent directories.
  1095.      * @throws SecurityException See {@link File#mkdirs()}.
  1096.      * @since 2.9.0
  1097.      */
  1098.     public static File createParentDirectories(final File file) throws IOException {
  1099.         return mkdirs(getParentFile(file));
  1100.     }

  1101.     /**
  1102.      * Gets the current directory.
  1103.      *
  1104.      * @return the current directory.
  1105.      * @since 2.12.0
  1106.      */
  1107.     public static File current() {
  1108.         return PathUtils.current().toFile();
  1109.     }

  1110.     /**
  1111.      * Decodes the specified URL as per RFC 3986, transforming
  1112.      * percent-encoded octets to characters by decoding with the UTF-8 character
  1113.      * set. This function is primarily intended for usage with
  1114.      * {@link java.net.URL} which unfortunately does not enforce proper URLs. As
  1115.      * such, this method will leniently accept invalid characters or malformed
  1116.      * percent-encoded octets and simply pass them literally through to the
  1117.      * result string. Except for rare edge cases, this will make unencoded URLs
  1118.      * pass through unaltered.
  1119.      *
  1120.      * @param url The URL to decode, may be {@code null}.
  1121.      * @return The decoded URL or {@code null} if the input was
  1122.      * {@code null}.
  1123.      */
  1124.     static String decodeUrl(final String url) {
  1125.         String decoded = url;
  1126.         if (url != null && url.indexOf('%') >= 0) {
  1127.             final int n = url.length();
  1128.             final StringBuilder builder = new StringBuilder();
  1129.             final ByteBuffer byteBuffer = ByteBuffer.allocate(n);
  1130.             for (int i = 0; i < n; ) {
  1131.                 if (url.charAt(i) == '%') {
  1132.                     try {
  1133.                         do {
  1134.                             final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16);
  1135.                             byteBuffer.put(octet);
  1136.                             i += 3;
  1137.                         } while (i < n && url.charAt(i) == '%');
  1138.                         continue;
  1139.                     } catch (final IndexOutOfBoundsException | NumberFormatException ignored) {
  1140.                         // malformed percent-encoded octet, fall through and
  1141.                         // append characters literally
  1142.                     } finally {
  1143.                         if (byteBuffer.position() > 0) {
  1144.                             byteBuffer.flip();
  1145.                             builder.append(StandardCharsets.UTF_8.decode(byteBuffer).toString());
  1146.                             byteBuffer.clear();
  1147.                         }
  1148.                     }
  1149.                 }
  1150.                 builder.append(url.charAt(i++));
  1151.             }
  1152.             decoded = builder.toString();
  1153.         }
  1154.         return decoded;
  1155.     }

  1156.     /**
  1157.      * Deletes the given File but throws an IOException if it cannot, unlike {@link File#delete()} which returns a
  1158.      * boolean.
  1159.      *
  1160.      * @param file The file to delete.
  1161.      * @return the given file.
  1162.      * @throws NullPointerException     if the parameter is {@code null}
  1163.      * @throws IOException              if the file cannot be deleted.
  1164.      * @see File#delete()
  1165.      * @since 2.9.0
  1166.      */
  1167.     public static File delete(final File file) throws IOException {
  1168.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1169.         Files.delete(file.toPath());
  1170.         return file;
  1171.     }

  1172.     /**
  1173.      * Deletes a directory recursively.
  1174.      *
  1175.      * @param directory directory to delete
  1176.      * @throws IOException              in case deletion is unsuccessful
  1177.      * @throws NullPointerException     if the parameter is {@code null}
  1178.      * @throws IllegalArgumentException if {@code directory} is not a directory
  1179.      */
  1180.     public static void deleteDirectory(final File directory) throws IOException {
  1181.         Objects.requireNonNull(directory, "directory");
  1182.         if (!directory.exists()) {
  1183.             return;
  1184.         }
  1185.         if (!isSymlink(directory)) {
  1186.             cleanDirectory(directory);
  1187.         }
  1188.         delete(directory);
  1189.     }

  1190.     /**
  1191.      * Schedules a directory recursively for deletion on JVM exit.
  1192.      *
  1193.      * @param directory directory to delete, must not be {@code null}
  1194.      * @throws NullPointerException if the directory is {@code null}
  1195.      * @throws IOException          in case deletion is unsuccessful
  1196.      */
  1197.     private static void deleteDirectoryOnExit(final File directory) throws IOException {
  1198.         if (!directory.exists()) {
  1199.             return;
  1200.         }
  1201.         directory.deleteOnExit();
  1202.         if (!isSymlink(directory)) {
  1203.             cleanDirectoryOnExit(directory);
  1204.         }
  1205.     }

  1206.     /**
  1207.      * Deletes a file, never throwing an exception. If file is a directory, delete it and all subdirectories.
  1208.      * <p>
  1209.      * The difference between File.delete() and this method are:
  1210.      * </p>
  1211.      * <ul>
  1212.      * <li>A directory to be deleted does not have to be empty.</li>
  1213.      * <li>No exceptions are thrown when a file or directory cannot be deleted.</li>
  1214.      * </ul>
  1215.      *
  1216.      * @param file file or directory to delete, can be {@code null}
  1217.      * @return {@code true} if the file or directory was deleted, otherwise
  1218.      * {@code false}
  1219.      * @since 1.4
  1220.      */
  1221.     public static boolean deleteQuietly(final File file) {
  1222.         if (file == null) {
  1223.             return false;
  1224.         }
  1225.         try {
  1226.             if (file.isDirectory()) {
  1227.                 cleanDirectory(file);
  1228.             }
  1229.         } catch (final Exception ignored) {
  1230.             // ignore
  1231.         }

  1232.         try {
  1233.             return file.delete();
  1234.         } catch (final Exception ignored) {
  1235.             return false;
  1236.         }
  1237.     }

  1238.     /**
  1239.      * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory).
  1240.      * <p>
  1241.      * Files are normalized before comparison.
  1242.      * </p>
  1243.      *
  1244.      * Edge cases:
  1245.      * <ul>
  1246.      * <li>A {@code directory} must not be null: if null, throw NullPointerException</li>
  1247.      * <li>A {@code directory} must be a directory: if not a directory, throw IllegalArgumentException</li>
  1248.      * <li>A directory does not contain itself: return false</li>
  1249.      * <li>A null child file is not contained in any parent: return false</li>
  1250.      * </ul>
  1251.      *
  1252.      * @param directory the file to consider as the parent.
  1253.      * @param child     the file to consider as the child.
  1254.      * @return true is the candidate leaf is under by the specified composite. False otherwise.
  1255.      * @throws IOException              if an IO error occurs while checking the files.
  1256.      * @throws NullPointerException if the parent is {@code null}.
  1257.      * @throws IllegalArgumentException if the parent is not a directory.
  1258.      * @see FilenameUtils#directoryContains(String, String)
  1259.      * @since 2.2
  1260.      */
  1261.     public static boolean directoryContains(final File directory, final File child) throws IOException {
  1262.         requireDirectoryExists(directory, "directory");

  1263.         if (child == null || !child.exists()) {
  1264.             return false;
  1265.         }

  1266.         // Canonicalize paths (normalizes relative paths)
  1267.         return FilenameUtils.directoryContains(directory.getCanonicalPath(), child.getCanonicalPath());
  1268.     }

  1269.     /**
  1270.      * Internal copy directory method. Creates all destination parent directories,
  1271.      * including any necessary but non-existent parent directories.
  1272.      *
  1273.      * @param srcDir the validated source directory, must not be {@code null}.
  1274.      * @param destDir the validated destination directory, must not be {@code null}.
  1275.      * @param fileFilter the filter to apply, null means copy all directories and files.
  1276.      * @param exclusionList List of files and directories to exclude from the copy, may be null.
  1277.      * @param preserveDirDate preserve the directories last modified dates.
  1278.      * @param copyOptions options specifying how the copy should be done, see {@link StandardCopyOption}.
  1279.      * @throws IOException if the directory was not created along with all its parent directories.
  1280.      * @throws IllegalArgumentException if {@code destDir} is not writable
  1281.      * @throws SecurityException See {@link File#mkdirs()}.
  1282.      */
  1283.     private static void doCopyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final List<String> exclusionList,
  1284.         final boolean preserveDirDate, final CopyOption... copyOptions) throws IOException {
  1285.         // recurse dirs, copy files.
  1286.         final File[] srcFiles = listFiles(srcDir, fileFilter);
  1287.         requireDirectoryIfExists(destDir, "destDir");
  1288.         mkdirs(destDir);
  1289.         for (final File srcFile : srcFiles) {
  1290.             final File dstFile = new File(destDir, srcFile.getName());
  1291.             if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) {
  1292.                 if (srcFile.isDirectory()) {
  1293.                     doCopyDirectory(srcFile, dstFile, fileFilter, exclusionList, preserveDirDate, copyOptions);
  1294.                 } else {
  1295.                     copyFile(srcFile, dstFile, preserveDirDate, copyOptions);
  1296.                 }
  1297.             }
  1298.         }
  1299.         // Do this last, as the above has probably affected directory metadata
  1300.         if (preserveDirDate) {
  1301.             setTimes(srcDir, destDir);
  1302.         }
  1303.     }

  1304.     /**
  1305.      * Deletes a file or directory. For a directory, delete it and all subdirectories.
  1306.      * <p>
  1307.      * The difference between File.delete() and this method are:
  1308.      * </p>
  1309.      * <ul>
  1310.      * <li>The directory does not have to be empty.</li>
  1311.      * <li>You get an exception when a file or directory cannot be deleted.</li>
  1312.      * </ul>
  1313.      *
  1314.      * @param file file or directory to delete, must not be {@code null}.
  1315.      * @throws NullPointerException  if the file is {@code null}.
  1316.      * @throws FileNotFoundException if the file was not found.
  1317.      * @throws IOException           in case deletion is unsuccessful.
  1318.      */
  1319.     public static void forceDelete(final File file) throws IOException {
  1320.         forceDelete(file, true);
  1321.     }

  1322.     /**
  1323.      * Deletes a file or directory. For a directory, delete it and all subdirectories.
  1324.      * <p>
  1325.      * The difference between File.delete() and this method are:
  1326.      * </p>
  1327.      * <ul>
  1328.      * <li>The directory does not have to be empty.</li>
  1329.      * <li>You get an exception when a file or directory cannot be deleted.</li>
  1330.      * </ul>
  1331.      *
  1332.      * @param file file or directory to delete, must not be {@code null}.
  1333.      * @param strict whether to throw a FileNotFoundException.
  1334.      * @throws NullPointerException  if the file is {@code null}.
  1335.      * @throws FileNotFoundException if the file was not found.
  1336.      * @throws IOException           in case deletion is unsuccessful.
  1337.      */
  1338.     private static void forceDelete(final File file, final boolean strict) throws IOException {
  1339.         checkExists(file, strict); // fail-fast
  1340.         final Counters.PathCounters deleteCounters;
  1341.         try {
  1342.             deleteCounters = PathUtils.delete(file.toPath(), PathUtils.EMPTY_LINK_OPTION_ARRAY, StandardDeleteOption.OVERRIDE_READ_ONLY);
  1343.         } catch (final NoSuchFileException e) {
  1344.             // Map NIO to IO exception
  1345.             final FileNotFoundException nioEx = new FileNotFoundException("Cannot delete file: " + file);
  1346.             nioEx.initCause(e);
  1347.             throw nioEx;
  1348.         } catch (final IOException e) {
  1349.             throw new IOException("Cannot delete file: " + file, e);
  1350.         }
  1351.         if (deleteCounters.getFileCounter().get() < 1 && deleteCounters.getDirectoryCounter().get() < 1) {
  1352.             // didn't find a file to delete.
  1353.             throw new FileNotFoundException("File does not exist: " + file);
  1354.         }
  1355.     }

  1356.     /**
  1357.      * Schedules a file to be deleted when JVM exits.
  1358.      * If file is directory delete it and all subdirectories.
  1359.      *
  1360.      * @param file file or directory to delete, must not be {@code null}.
  1361.      * @throws NullPointerException if the file is {@code null}.
  1362.      * @throws IOException          in case deletion is unsuccessful.
  1363.      */
  1364.     public static void forceDeleteOnExit(final File file) throws IOException {
  1365.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1366.         if (file.isDirectory()) {
  1367.             deleteDirectoryOnExit(file);
  1368.         } else {
  1369.             file.deleteOnExit();
  1370.         }
  1371.     }

  1372.     /**
  1373.      * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is
  1374.      * null, nothing happens.
  1375.      * <p>
  1376.      * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure.
  1377.      * </p>
  1378.      *
  1379.      * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens.
  1380.      * @throws IOException       if the directory was not created along with all its parent directories.
  1381.      * @throws IOException       if the given file object is not a directory.
  1382.      * @throws SecurityException See {@link File#mkdirs()}.
  1383.      * @see File#mkdirs()
  1384.      */
  1385.     public static void forceMkdir(final File directory) throws IOException {
  1386.         mkdirs(directory);
  1387.     }

  1388.     /**
  1389.      * Creates all directories for a File object, including any necessary but non-existent parent directories. If the parent directory already exists or is
  1390.      * null, nothing happens.
  1391.      * <p>
  1392.      * Calls {@link File#mkdirs()} for the parent of {@code file}.
  1393.      * </p>
  1394.      *
  1395.      * @param file file with parents to create, must not be {@code null}.
  1396.      * @throws NullPointerException if the file is {@code null}.
  1397.      * @throws IOException          if the directory was not created along with all its parent directories.
  1398.      * @throws SecurityException    See {@link File#mkdirs()}.
  1399.      * @see File#mkdirs()
  1400.      * @since 2.5
  1401.      */
  1402.     public static void forceMkdirParent(final File file) throws IOException {
  1403.         forceMkdir(getParentFile(Objects.requireNonNull(file, PROTOCOL_FILE)));
  1404.     }

  1405.     /**
  1406.      * Constructs a file from the set of name elements.
  1407.      *
  1408.      * @param directory the parent directory.
  1409.      * @param names the name elements.
  1410.      * @return the new file.
  1411.      * @since 2.1
  1412.      */
  1413.     public static File getFile(final File directory, final String... names) {
  1414.         Objects.requireNonNull(directory, "directory");
  1415.         Objects.requireNonNull(names, "names");
  1416.         File file = directory;
  1417.         for (final String name : names) {
  1418.             file = new File(file, name);
  1419.         }
  1420.         return file;
  1421.     }

  1422.     /**
  1423.      * Constructs a file from the set of name elements.
  1424.      *
  1425.      * @param names the name elements.
  1426.      * @return the file.
  1427.      * @since 2.1
  1428.      */
  1429.     public static File getFile(final String... names) {
  1430.         Objects.requireNonNull(names, "names");
  1431.         File file = null;
  1432.         for (final String name : names) {
  1433.             if (file == null) {
  1434.                 file = new File(name);
  1435.             } else {
  1436.                 file = new File(file, name);
  1437.             }
  1438.         }
  1439.         return file;
  1440.     }

  1441.     /**
  1442.      * Gets the parent of the given file. The given file may be null. Note that a file's parent may be null as well.
  1443.      *
  1444.      * @param file The file to query, may be null.
  1445.      * @return The parent file or {@code null}. Note that a file's parent may be null as well.
  1446.      */
  1447.     private static File getParentFile(final File file) {
  1448.         return file == null ? null : file.getParentFile();
  1449.     }

  1450.     /**
  1451.      * Returns a {@link File} representing the system temporary directory.
  1452.      *
  1453.      * @return the system temporary directory as a File
  1454.      * @since 2.0
  1455.      */
  1456.     public static File getTempDirectory() {
  1457.         return new File(getTempDirectoryPath());
  1458.     }

  1459.     /**
  1460.      * Returns the path to the system temporary directory.
  1461.      *
  1462.      * WARNING: this method relies on the Java system property 'java.io.tmpdir'
  1463.      * which may or may not have a trailing file separator.
  1464.      * This can affect code that uses String processing to manipulate pathnames rather
  1465.      * than the standard libary methods in classes such as {@link File}
  1466.      *
  1467.      * @return the path to the system temporary directory as a String
  1468.      * @since 2.0
  1469.      */
  1470.     public static String getTempDirectoryPath() {
  1471.         return System.getProperty("java.io.tmpdir");
  1472.     }

  1473.     /**
  1474.      * Returns a {@link File} representing the user's home directory.
  1475.      *
  1476.      * @return the user's home directory.
  1477.      * @since 2.0
  1478.      */
  1479.     public static File getUserDirectory() {
  1480.         return new File(getUserDirectoryPath());
  1481.     }

  1482.     /**
  1483.      * Returns the path to the user's home directory.
  1484.      *
  1485.      * @return the path to the user's home directory.
  1486.      * @since 2.0
  1487.      */
  1488.     public static String getUserDirectoryPath() {
  1489.         return System.getProperty("user.home");
  1490.     }

  1491.     /**
  1492.      * Tests whether the specified {@link File} is a directory or not. Implemented as a
  1493.      * null-safe delegate to {@link Files#isDirectory(Path path, LinkOption... options)}.
  1494.      *
  1495.      * @param   file the path to the file.
  1496.      * @param   options options indicating how symbolic links are handled
  1497.      * @return  {@code true} if the file is a directory; {@code false} if
  1498.      *          the path is null, the file does not exist, is not a directory, or it cannot
  1499.      *          be determined if the file is a directory or not.
  1500.      * @throws SecurityException     In the case of the default provider, and a security manager is installed, the
  1501.      *                               {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read
  1502.      *                               access to the directory.
  1503.      * @since 2.9.0
  1504.      */
  1505.     public static boolean isDirectory(final File file, final LinkOption... options) {
  1506.         return file != null && Files.isDirectory(file.toPath(), options);
  1507.     }

  1508.     /**
  1509.      * Tests whether the directory is empty.
  1510.      *
  1511.      * @param directory the directory to query.
  1512.      * @return whether the directory is empty.
  1513.      * @throws IOException if an I/O error occurs.
  1514.      * @throws NotDirectoryException if the file could not otherwise be opened because it is not a directory
  1515.      *                               <em>(optional specific exception)</em>.
  1516.      * @since 2.9.0
  1517.      */
  1518.     public static boolean isEmptyDirectory(final File directory) throws IOException {
  1519.         return PathUtils.isEmptyDirectory(directory.toPath());
  1520.     }

  1521.     /**
  1522.      * 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 UncheckedIOException if an I/O error occurs
  1536.      * @throws NullPointerException if the file or local date is {@code null}.
  1537.      * @since 2.8.0
  1538.      */
  1539.     public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate) {
  1540.         return isFileNewer(file, chronoLocalDate, LocalTime.MAX);
  1541.     }

  1542.     /**
  1543.      * 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 UncheckedIOException if an I/O error occurs
  1557.      * @throws NullPointerException if the file, local date or zone ID is {@code null}.
  1558.      * @since 2.8.0
  1559.      */
  1560.     public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) {
  1561.         Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
  1562.         Objects.requireNonNull(localTime, "localTime");
  1563.         return isFileNewer(file, chronoLocalDate.atTime(localTime));
  1564.     }

  1565.     /**
  1566.      * 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 UncheckedIOException if an I/O error occurs
  1575.      * @throws NullPointerException if the file, local date or zone ID is {@code null}
  1576.      * @since 2.12.0
  1577.      */
  1578.     public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) {
  1579.         Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
  1580.         Objects.requireNonNull(offsetTime, "offsetTime");
  1581.         return isFileNewer(file, chronoLocalDate.atTime(offsetTime.toLocalTime()));
  1582.     }

  1583.     /**
  1584.      * 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 UncheckedIOException if an I/O error occurs
  1597.      * @throws NullPointerException if the file or local date time is {@code null}.
  1598.      * @since 2.8.0
  1599.      */
  1600.     public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) {
  1601.         return isFileNewer(file, chronoLocalDateTime, ZoneId.systemDefault());
  1602.     }

  1603.     /**
  1604.      * 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 UncheckedIOException if an I/O error occurs
  1613.      * @throws NullPointerException if the file, local date time or zone ID is {@code null}.
  1614.      * @since 2.8.0
  1615.      */
  1616.     public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) {
  1617.         Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime");
  1618.         Objects.requireNonNull(zoneId, "zoneId");
  1619.         return isFileNewer(file, chronoLocalDateTime.atZone(zoneId));
  1620.     }

  1621.     /**
  1622.      * 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.      * @throws UncheckedIOException if an I/O error occurs
  1630.      * @since 2.8.0
  1631.      */
  1632.     public static boolean isFileNewer(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) {
  1633.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1634.         Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
  1635.         return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), chronoZonedDateTime));
  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 UncheckedIOException if an I/O error occurs
  1645.      * @throws NullPointerException if the file or date is {@code null}.
  1646.      */
  1647.     public static boolean isFileNewer(final File file, final Date date) {
  1648.         Objects.requireNonNull(date, "date");
  1649.         return isFileNewer(file, date.getTime());
  1650.     }

  1651.     /**
  1652.      * 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 UncheckedIOException if the reference file doesn't exist.
  1660.      */
  1661.     public static boolean isFileNewer(final File file, final File reference) {
  1662.         return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), reference.toPath()));
  1663.     }

  1664.     /**
  1665.      * Tests if the specified {@link File} is newer than the specified {@link FileTime}.
  1666.      *
  1667.      * @param file the {@link File} of which the modification date must be compared.
  1668.      * @param fileTime the file time reference.
  1669.      * @return true if the {@link File} exists and has been modified after the given {@link FileTime}.
  1670.      * @throws IOException if an I/O error occurs.
  1671.      * @throws NullPointerException if the file or local date is {@code null}.
  1672.      * @since 2.12.0
  1673.      */
  1674.     public static boolean isFileNewer(final File file, final FileTime fileTime) throws IOException {
  1675.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1676.         return PathUtils.isNewer(file.toPath(), fileTime);
  1677.     }

  1678.     /**
  1679.      * Tests if the specified {@link File} is newer than the specified {@link Instant}.
  1680.      *
  1681.      * @param file the {@link File} of which the modification date must be compared.
  1682.      * @param instant the date reference.
  1683.      * @return true if the {@link File} exists and has been modified after the given {@link Instant}.
  1684.      * @throws NullPointerException if the file or instant is {@code null}.
  1685.      * @throws UncheckedIOException if an I/O error occurs
  1686.      * @since 2.8.0
  1687.      */
  1688.     public static boolean isFileNewer(final File file, final Instant instant) {
  1689.         Objects.requireNonNull(instant, "instant");
  1690.         return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), instant));
  1691.     }

  1692.     /**
  1693.      * Tests if the specified {@link File} is newer than the specified time reference.
  1694.      *
  1695.      * @param file       the {@link File} of which the modification date must be compared.
  1696.      * @param timeMillis the time reference measured in milliseconds since the
  1697.      *                   epoch (00:00:00 GMT, January 1, 1970).
  1698.      * @return true if the {@link File} exists and has been modified after the given time reference.
  1699.      * @throws UncheckedIOException if an I/O error occurs
  1700.      * @throws NullPointerException if the file is {@code null}.
  1701.      */
  1702.     public static boolean isFileNewer(final File file, final long timeMillis) {
  1703.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1704.         return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), timeMillis));
  1705.     }

  1706.     /**
  1707.      * Tests if the specified {@link File} is newer than the specified {@link OffsetDateTime}.
  1708.      *
  1709.      * @param file the {@link File} of which the modification date must be compared
  1710.      * @param offsetDateTime the date reference
  1711.      * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}.
  1712.      * @throws UncheckedIOException if an I/O error occurs
  1713.      * @throws NullPointerException if the file or zoned date time is {@code null}
  1714.      * @since 2.12.0
  1715.      */
  1716.     public static boolean isFileNewer(final File file, final OffsetDateTime offsetDateTime) {
  1717.         Objects.requireNonNull(offsetDateTime, "offsetDateTime");
  1718.         return isFileNewer(file, offsetDateTime.toInstant());
  1719.     }

  1720.     /**
  1721.      * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate}
  1722.      * at the end of day.
  1723.      *
  1724.      * <p>Note: The input date is assumed to be in the system default time-zone with the time
  1725.      * part set to the current time. To use a non-default time-zone use the method
  1726.      * {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
  1727.      * isFileOlder(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where
  1728.      * {@code zoneId} is a valid {@link ZoneId}.
  1729.      *
  1730.      * @param file            the {@link File} of which the modification date must be compared.
  1731.      * @param chronoLocalDate the date reference.
  1732.      * @return true if the {@link File} exists and has been modified before the given
  1733.      * {@link ChronoLocalDate} at the current time.
  1734.      * @throws NullPointerException if the file or local date is {@code null}.
  1735.      * @throws UncheckedIOException if an I/O error occurs
  1736.      * @see ZoneId#systemDefault()
  1737.      * @see LocalTime#now()
  1738.      * @since 2.8.0
  1739.      */
  1740.     public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate) {
  1741.         return isFileOlder(file, chronoLocalDate, LocalTime.MAX);
  1742.     }

  1743.     /**
  1744.      * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate}
  1745.      * at the specified {@link LocalTime}.
  1746.      *
  1747.      * <p>Note: The input date and time are assumed to be in the system default time-zone. To use a
  1748.      * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
  1749.      * isFileOlder(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid
  1750.      * {@link ZoneId}.
  1751.      *
  1752.      * @param file            the {@link File} of which the modification date must be compared.
  1753.      * @param chronoLocalDate the date reference.
  1754.      * @param localTime       the time reference.
  1755.      * @return true if the {@link File} exists and has been modified before the
  1756.      * given {@link ChronoLocalDate} at the specified time.
  1757.      * @throws UncheckedIOException if an I/O error occurs
  1758.      * @throws NullPointerException if the file, local date or local time is {@code null}.
  1759.      * @see ZoneId#systemDefault()
  1760.      * @since 2.8.0
  1761.      */
  1762.     public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) {
  1763.         Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
  1764.         Objects.requireNonNull(localTime, "localTime");
  1765.         return isFileOlder(file, chronoLocalDate.atTime(localTime));
  1766.     }

  1767.     /**
  1768.      * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate} at the specified
  1769.      * {@link OffsetTime}.
  1770.      *
  1771.      * @param file the {@link File} of which the modification date must be compared
  1772.      * @param chronoLocalDate the date reference
  1773.      * @param offsetTime the time reference
  1774.      * @return true if the {@link File} exists and has been modified after the given {@link ChronoLocalDate} at the given
  1775.      *         {@link OffsetTime}.
  1776.      * @throws NullPointerException if the file, local date or zone ID is {@code null}
  1777.      * @throws UncheckedIOException if an I/O error occurs
  1778.      * @since 2.12.0
  1779.      */
  1780.     public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) {
  1781.         Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
  1782.         Objects.requireNonNull(offsetTime, "offsetTime");
  1783.         return isFileOlder(file, chronoLocalDate.atTime(offsetTime.toLocalTime()));
  1784.     }

  1785.     /**
  1786.      * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime}
  1787.      * at the system-default time zone.
  1788.      *
  1789.      * <p>Note: The input date and time is assumed to be in the system default time-zone. To use a
  1790.      * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
  1791.      * isFileOlder(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid
  1792.      * {@link ZoneId}.
  1793.      *
  1794.      * @param file                the {@link File} of which the modification date must be compared.
  1795.      * @param chronoLocalDateTime the date reference.
  1796.      * @return true if the {@link File} exists and has been modified before the given
  1797.      * {@link ChronoLocalDateTime} at the system-default time zone.
  1798.      * @throws NullPointerException if the file or local date time is {@code null}.
  1799.      * @throws UncheckedIOException if an I/O error occurs
  1800.      * @see ZoneId#systemDefault()
  1801.      * @since 2.8.0
  1802.      */
  1803.     public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) {
  1804.         return isFileOlder(file, chronoLocalDateTime, ZoneId.systemDefault());
  1805.     }

  1806.     /**
  1807.      * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime}
  1808.      * at the specified {@link ZoneId}.
  1809.      *
  1810.      * @param file          the {@link File} of which the modification date must be compared.
  1811.      * @param chronoLocalDateTime the date reference.
  1812.      * @param zoneId        the time zone.
  1813.      * @return true if the {@link File} exists and has been modified before the given
  1814.      * {@link ChronoLocalDateTime} at the given {@link ZoneId}.
  1815.      * @throws NullPointerException if the file, local date time or zone ID is {@code null}.
  1816.      * @throws UncheckedIOException if an I/O error occurs
  1817.      * @since 2.8.0
  1818.      */
  1819.     public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) {
  1820.         Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime");
  1821.         Objects.requireNonNull(zoneId, "zoneId");
  1822.         return isFileOlder(file, chronoLocalDateTime.atZone(zoneId));
  1823.     }

  1824.     /**
  1825.      * Tests if the specified {@link File} is older than the specified {@link ChronoZonedDateTime}.
  1826.      *
  1827.      * @param file                the {@link File} of which the modification date must be compared.
  1828.      * @param chronoZonedDateTime the date reference.
  1829.      * @return true if the {@link File} exists and has been modified before the given
  1830.      * {@link ChronoZonedDateTime}.
  1831.      * @throws NullPointerException if the file or zoned date time is {@code null}.
  1832.      * @throws UncheckedIOException if an I/O error occurs
  1833.      * @since 2.8.0
  1834.      */
  1835.     public static boolean isFileOlder(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) {
  1836.         Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
  1837.         return isFileOlder(file, chronoZonedDateTime.toInstant());
  1838.     }

  1839.     /**
  1840.      * Tests if the specified {@link File} is older than the specified {@link Date}.
  1841.      *
  1842.      * @param file the {@link File} of which the modification date must be compared.
  1843.      * @param date the date reference.
  1844.      * @return true if the {@link File} exists and has been modified before the given {@link Date}.
  1845.      * @throws NullPointerException if the file or date is {@code null}.
  1846.      * @throws UncheckedIOException if an I/O error occurs
  1847.      */
  1848.     public static boolean isFileOlder(final File file, final Date date) {
  1849.         Objects.requireNonNull(date, "date");
  1850.         return isFileOlder(file, date.getTime());
  1851.     }

  1852.     /**
  1853.      * Tests if the specified {@link File} is older than the reference {@link File}.
  1854.      *
  1855.      * @param file      the {@link File} of which the modification date must be compared.
  1856.      * @param reference the {@link File} of which the modification date is used.
  1857.      * @return true if the {@link File} exists and has been modified before the reference {@link File}.
  1858.      * @throws NullPointerException if the file or reference file is {@code null}.
  1859.      * @throws FileNotFoundException if the reference file doesn't exist.
  1860.      * @throws UncheckedIOException if an I/O error occurs
  1861.      */
  1862.     public static boolean isFileOlder(final File file, final File reference) throws FileNotFoundException {
  1863.         return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), reference.toPath()));
  1864.     }

  1865.     /**
  1866.      * Tests if the specified {@link File} is older than the specified {@link FileTime}.
  1867.      *
  1868.      * @param file the {@link File} of which the modification date must be compared.
  1869.      * @param fileTime the file time reference.
  1870.      * @return true if the {@link File} exists and has been modified before the given {@link FileTime}.
  1871.      * @throws IOException if an I/O error occurs.
  1872.      * @throws NullPointerException if the file or local date is {@code null}.
  1873.      * @since 2.12.0
  1874.      */
  1875.     public static boolean isFileOlder(final File file, final FileTime fileTime) throws IOException {
  1876.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1877.         return PathUtils.isOlder(file.toPath(), fileTime);
  1878.     }

  1879.     /**
  1880.      * Tests if the specified {@link File} is older than the specified {@link Instant}.
  1881.      *
  1882.      * @param file    the {@link File} of which the modification date must be compared.
  1883.      * @param instant the date reference.
  1884.      * @return true if the {@link File} exists and has been modified before the given {@link Instant}.
  1885.      * @throws NullPointerException if the file or instant is {@code null}.
  1886.      * @since 2.8.0
  1887.      */
  1888.     public static boolean isFileOlder(final File file, final Instant instant) {
  1889.         Objects.requireNonNull(instant, "instant");
  1890.         return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), instant));
  1891.     }

  1892.     /**
  1893.      * Tests if the specified {@link File} is older than the specified time reference.
  1894.      *
  1895.      * @param file       the {@link File} of which the modification date must be compared.
  1896.      * @param timeMillis the time reference measured in milliseconds since the
  1897.      *                   epoch (00:00:00 GMT, January 1, 1970).
  1898.      * @return true if the {@link File} exists and has been modified before the given time reference.
  1899.      * @throws NullPointerException if the file is {@code null}.
  1900.      * @throws UncheckedIOException if an I/O error occurs
  1901.      */
  1902.     public static boolean isFileOlder(final File file, final long timeMillis) {
  1903.         Objects.requireNonNull(file, PROTOCOL_FILE);
  1904.         return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), timeMillis));
  1905.     }

  1906.     /**
  1907.      * Tests if the specified {@link File} is older than the specified {@link OffsetDateTime}.
  1908.      *
  1909.      * @param file the {@link File} of which the modification date must be compared
  1910.      * @param offsetDateTime the date reference
  1911.      * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}.
  1912.      * @throws NullPointerException if the file or zoned date time is {@code null}
  1913.      * @since 2.12.0
  1914.      */
  1915.     public static boolean isFileOlder(final File file, final OffsetDateTime offsetDateTime) {
  1916.         Objects.requireNonNull(offsetDateTime, "offsetDateTime");
  1917.         return isFileOlder(file, offsetDateTime.toInstant());
  1918.     }

  1919.     /**
  1920.      * Tests whether the given URL is a file URL.
  1921.      *
  1922.      * @param url The URL to test.
  1923.      * @return Whether the given URL is a file URL.
  1924.      */
  1925.     private static boolean isFileProtocol(final URL url) {
  1926.         return PROTOCOL_FILE.equalsIgnoreCase(url.getProtocol());
  1927.     }

  1928.     /**
  1929.      * Tests whether the specified {@link File} is a regular file or not. Implemented as a
  1930.      * null-safe delegate to {@link Files#isRegularFile(Path path, LinkOption... options)}.
  1931.      *
  1932.      * @param   file the path to the file.
  1933.      * @param   options options indicating how symbolic links are handled
  1934.      * @return  {@code true} if the file is a regular file; {@code false} if
  1935.      *          the path is null, the file does not exist, is not a regular file, or it cannot
  1936.      *          be determined if the file is a regular file or not.
  1937.      * @throws SecurityException     In the case of the default provider, and a security manager is installed, the
  1938.      *                               {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read
  1939.      *                               access to the directory.
  1940.      * @since 2.9.0
  1941.      */
  1942.     public static boolean isRegularFile(final File file, final LinkOption... options) {
  1943.         return file != null && Files.isRegularFile(file.toPath(), options);
  1944.     }

  1945.     /**
  1946.      * Tests whether the specified file is a symbolic link rather than an actual file.
  1947.      * <p>
  1948.      * This method delegates to {@link Files#isSymbolicLink(Path path)}
  1949.      * </p>
  1950.      *
  1951.      * @param file the file to test.
  1952.      * @return true if the file is a symbolic link, see {@link Files#isSymbolicLink(Path path)}.
  1953.      * @since 2.0
  1954.      * @see Files#isSymbolicLink(Path)
  1955.      */
  1956.     public static boolean isSymlink(final File file) {
  1957.         return file != null && Files.isSymbolicLink(file.toPath());
  1958.     }

  1959.     /**
  1960.      * 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 {@link 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.      * Iterates over the files in a given directory (and optionally
  1984.      * its subdirectories) which match an array of extensions.
  1985.      * <p>
  1986.      * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
  1987.      * </p>
  1988.      *
  1989.      * @param directory  the directory to search in
  1990.      * @param extensions an array of extensions, for example, {"java","xml"}. If this
  1991.      *                   parameter is {@code null}, all files are returned.
  1992.      * @param recursive  if true all subdirectories are searched as well
  1993.      * @return an iterator of {@link File} with the matching files
  1994.      * @since 1.2
  1995.      */
  1996.     public static Iterator<File> iterateFiles(final File directory, final String[] extensions, final boolean recursive) {
  1997.         return StreamIterator.iterator(Uncheck.get(() -> streamFiles(directory, recursive, extensions)));
  1998.     }

  1999.     /**
  2000.      * Iterates over the files in given directory (and optionally
  2001.      * its subdirectories).
  2002.      * <p>
  2003.      * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
  2004.      * </p>
  2005.      * <p>
  2006.      * All files found are filtered by an IOFileFilter.
  2007.      * </p>
  2008.      * <p>
  2009.      * The resulting iterator includes the subdirectories themselves.
  2010.      * </p>
  2011.      *
  2012.      * @param directory  the directory to search in
  2013.      * @param fileFilter filter to apply when finding files.
  2014.      * @param dirFilter  optional filter to apply when finding subdirectories.
  2015.      *                   If this parameter is {@code null}, subdirectories will not be included in the
  2016.      *                   search. Use TrueFileFilter.INSTANCE to match all directories.
  2017.      * @return an iterator of {@link File} for the matching files
  2018.      * @see org.apache.commons.io.filefilter.FileFilterUtils
  2019.      * @see org.apache.commons.io.filefilter.NameFileFilter
  2020.      * @since 2.2
  2021.      */
  2022.     public static Iterator<File> iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
  2023.         return listFilesAndDirs(directory, fileFilter, dirFilter).iterator();
  2024.     }

  2025.     /**
  2026.      * Returns the last modification time in milliseconds via
  2027.      * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
  2028.      * <p>
  2029.      * For the best precision, use {@link #lastModifiedFileTime(File)}.
  2030.      * </p>
  2031.      * <p>
  2032.      * Use this method to avoid issues with {@link File#lastModified()} like
  2033.      * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
  2034.      * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
  2035.      * </p>
  2036.      *
  2037.      * @param file The File to query.
  2038.      * @return See {@link java.nio.file.attribute.FileTime#toMillis()}.
  2039.      * @throws IOException if an I/O error occurs.
  2040.      * @since 2.9.0
  2041.      */
  2042.     public static long lastModified(final File file) throws IOException {
  2043.         // https://bugs.openjdk.java.net/browse/JDK-8177809
  2044.         // File.lastModified() is losing milliseconds (always ends in 000)
  2045.         // This bug is in OpenJDK 8 and 9, and fixed in 10.
  2046.         return lastModifiedFileTime(file).toMillis();
  2047.     }

  2048.     /**
  2049.      * Returns the last modification {@link FileTime} via
  2050.      * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
  2051.      * <p>
  2052.      * Use this method to avoid issues with {@link File#lastModified()} like
  2053.      * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
  2054.      * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
  2055.      * </p>
  2056.      *
  2057.      * @param file The File to query.
  2058.      * @return See {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
  2059.      * @throws IOException if an I/O error occurs.
  2060.      * @since 2.12.0
  2061.      */
  2062.     public static FileTime lastModifiedFileTime(final File file) throws IOException {
  2063.         // https://bugs.openjdk.java.net/browse/JDK-8177809
  2064.         // File.lastModified() is losing milliseconds (always ends in 000)
  2065.         // This bug is in OpenJDK 8 and 9, and fixed in 10.
  2066.         return Files.getLastModifiedTime(Objects.requireNonNull(file, PROTOCOL_FILE).toPath());
  2067.     }

  2068.     /**
  2069.      * Returns the last modification time in milliseconds via
  2070.      * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
  2071.      * <p>
  2072.      * For the best precision, use {@link #lastModifiedFileTime(File)}.
  2073.      * </p>
  2074.      * <p>
  2075.      * Use this method to avoid issues with {@link File#lastModified()} like
  2076.      * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
  2077.      * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
  2078.      * </p>
  2079.      *
  2080.      * @param file The File to query.
  2081.      * @return See {@link java.nio.file.attribute.FileTime#toMillis()}.
  2082.      * @throws UncheckedIOException if an I/O error occurs.
  2083.      * @since 2.9.0
  2084.      */
  2085.     public static long lastModifiedUnchecked(final File file) {
  2086.         // https://bugs.openjdk.java.net/browse/JDK-8177809
  2087.         // File.lastModified() is losing milliseconds (always ends in 000)
  2088.         // This bug is in OpenJDK 8 and 9, and fixed in 10.
  2089.         return Uncheck.apply(FileUtils::lastModified, file);
  2090.     }

  2091.     /**
  2092.      * Returns an Iterator for the lines in a {@link File} using the default encoding for the VM.
  2093.      *
  2094.      * @param file the file to open for input, must not be {@code null}
  2095.      * @return an Iterator of the lines in the file, never {@code null}
  2096.      * @throws NullPointerException if file is {@code null}.
  2097.      * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
  2098.      *         other reason cannot be opened for reading.
  2099.      * @throws IOException if an I/O error occurs.
  2100.      * @see #lineIterator(File, String)
  2101.      * @since 1.3
  2102.      */
  2103.     public static LineIterator lineIterator(final File file) throws IOException {
  2104.         return lineIterator(file, null);
  2105.     }

  2106.     /**
  2107.      * Returns an Iterator for the lines in a {@link File}.
  2108.      * <p>
  2109.      * This method opens an {@link InputStream} for the file.
  2110.      * When you have finished with the iterator you should close the stream
  2111.      * to free internal resources. This can be done by using a try-with-resources block or calling the
  2112.      * {@link LineIterator#close()} method.
  2113.      * </p>
  2114.      * <p>
  2115.      * The recommended usage pattern is:
  2116.      * </p>
  2117.      * <pre>
  2118.      * LineIterator it = FileUtils.lineIterator(file, StandardCharsets.UTF_8.name());
  2119.      * try {
  2120.      *   while (it.hasNext()) {
  2121.      *     String line = it.nextLine();
  2122.      *     /// do something with line
  2123.      *   }
  2124.      * } finally {
  2125.      *   LineIterator.closeQuietly(iterator);
  2126.      * }
  2127.      * </pre>
  2128.      * <p>
  2129.      * If an exception occurs during the creation of the iterator, the
  2130.      * underlying stream is closed.
  2131.      * </p>
  2132.      *
  2133.      * @param file     the file to open for input, must not be {@code null}
  2134.      * @param charsetName the name of the requested charset, {@code null} means platform default
  2135.      * @return a LineIterator for lines in the file, never {@code null}; MUST be closed by the caller.
  2136.      * @throws NullPointerException if file is {@code null}.
  2137.      * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
  2138.      *         other reason cannot be opened for reading.
  2139.      * @throws IOException if an I/O error occurs.
  2140.      * @since 1.2
  2141.      */
  2142.     @SuppressWarnings("resource") // Caller closes the result LineIterator.
  2143.     public static LineIterator lineIterator(final File file, final String charsetName) throws IOException {
  2144.         InputStream inputStream = null;
  2145.         try {
  2146.             inputStream = Files.newInputStream(file.toPath());
  2147.             return IOUtils.lineIterator(inputStream, charsetName);
  2148.         } catch (final IOException | RuntimeException ex) {
  2149.             IOUtils.closeQuietly(inputStream, ex::addSuppressed);
  2150.             throw ex;
  2151.         }
  2152.     }

  2153.     private static AccumulatorPathVisitor listAccumulate(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter,
  2154.             final FileVisitOption... options) throws IOException {
  2155.         final boolean isDirFilterSet = dirFilter != null;
  2156.         final FileEqualsFileFilter rootDirFilter = new FileEqualsFileFilter(directory);
  2157.         final PathFilter dirPathFilter = isDirFilterSet ? rootDirFilter.or(dirFilter) : rootDirFilter;
  2158.         // @formatter:off
  2159.         final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.builder()
  2160.                 .setPathCounters(Counters.noopPathCounters())
  2161.                 .setFileFilter(fileFilter)
  2162.                 .setDirectoryFilter(dirPathFilter)
  2163.                 .setVisitFileFailedFunction((p, e) -> FileVisitResult.CONTINUE)
  2164.                 .get();
  2165.         // @formatter:on
  2166.         final Set<FileVisitOption> optionSet = new HashSet<>();
  2167.         if (options != null) {
  2168.             Collections.addAll(optionSet, options);
  2169.         }
  2170.         Files.walkFileTree(directory.toPath(), optionSet, toMaxDepth(isDirFilterSet), visitor);
  2171.         return visitor;
  2172.     }

  2173.     /**
  2174.      * Lists files in a directory, asserting that the supplied directory exists and is a directory.
  2175.      *
  2176.      * @param directory  The directory to list.
  2177.      * @param fileFilter Optional file filter, may be null.
  2178.      * @return The files in the directory, never {@code null}.
  2179.      * @throws NullPointerException     if the {@code directory} is {@code null}.
  2180.      * @throws IllegalArgumentException if the {@code directory} exists but is not a directory.
  2181.      * @throws IOException              if an I/O error occurs per {@link File#listFiles()} and {@link File#listFiles(FileFilter)}.
  2182.      * @throws SecurityException        If a security manager exists and its {@link SecurityManager#checkRead(String)} method denies read access to the
  2183.      *                                  directory.
  2184.      */
  2185.     private static File[] listFiles(final File directory, final FileFilter fileFilter) throws IOException {
  2186.         requireDirectoryExists(directory, "directory");
  2187.         final File[] files = directory.listFiles(fileFilter);
  2188.         if (files == null) {
  2189.             // null if the directory does not denote a directory, or if an I/O error occurs.
  2190.             throw new IOException("Unknown I/O error listing contents of directory: " + directory);
  2191.         }
  2192.         return files;
  2193.     }

  2194.     /**
  2195.      * 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 {@link 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 toList(visitor.getFileList().stream().map(Path::toFile));
  2227.     }

  2228.     /**
  2229.      * Lists Files in the given {@code directory}, adding each file to the given list.
  2230.      *
  2231.      * @param directory A File for an assumed directory, not null.
  2232.      * @param files The list to add found Files, not null.
  2233.      * @param recursive Whether or not to recurse into subdirectories.
  2234.      * @param filter How to filter files, not null.
  2235.      */
  2236.     @SuppressWarnings("null")
  2237.     private static void listFiles(final File directory, final List<File> files, final boolean recursive, final FilenameFilter filter) {
  2238.         final File[] listFiles = directory.listFiles();
  2239.         if (listFiles != null) {
  2240.             // Only allocate if you must.
  2241.             final List<File> dirs = recursive ? new ArrayList<>() : null;
  2242.             Arrays.stream(listFiles).forEach(f -> {
  2243.                 if (recursive && f.isDirectory()) {
  2244.                     dirs.add(f);
  2245.                 } else if (f.isFile() && filter.accept(directory, f.getName())) {
  2246.                     files.add(f);
  2247.                 }
  2248.             });
  2249.             if (recursive) {
  2250.                 dirs.forEach(d -> listFiles(d, files, true, filter));
  2251.             }
  2252.         }
  2253.     }

  2254.     /**
  2255.      * Lists files within a given directory (and optionally its subdirectories)
  2256.      * which match an array of extensions.
  2257.      *
  2258.      * @param directory  the directory to search in
  2259.      * @param extensions an array of extensions, for example, {"java","xml"}. If this
  2260.      *                   parameter is {@code null}, all files are returned.
  2261.      * @param recursive  if true all subdirectories are searched as well
  2262.      * @return a collection of {@link File} with the matching files
  2263.      */
  2264.     public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) {
  2265.         // IO-856: Don't use NIO to path walk, allocate as little as possible while traversing.
  2266.         final List<File> files = new ArrayList<>();
  2267.         final FilenameFilter filter = extensions != null ? toSuffixFileFilter(extensions) : TrueFileFilter.INSTANCE;
  2268.         listFiles(directory, files, recursive, filter);
  2269.         return files;
  2270.     }

  2271.     /**
  2272.      * Finds files within a given directory (and optionally its
  2273.      * subdirectories). All files found are filtered by an IOFileFilter.
  2274.      * <p>
  2275.      * The resulting collection includes the starting directory and
  2276.      * any subdirectories that match the directory filter.
  2277.      * </p>
  2278.      *
  2279.      * @param directory  the directory to search in
  2280.      * @param fileFilter filter to apply when finding files.
  2281.      * @param dirFilter  optional filter to apply when finding subdirectories.
  2282.      *                   If this parameter is {@code null}, subdirectories will not be included in the
  2283.      *                   search. Use TrueFileFilter.INSTANCE to match all directories.
  2284.      * @return a collection of {@link File} with the matching files
  2285.      * @see org.apache.commons.io.FileUtils#listFiles
  2286.      * @see org.apache.commons.io.filefilter.FileFilterUtils
  2287.      * @see org.apache.commons.io.filefilter.NameFileFilter
  2288.      * @since 2.2
  2289.      */
  2290.     public static Collection<File> listFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
  2291.         final AccumulatorPathVisitor visitor = Uncheck.apply(d -> listAccumulate(d, fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS),
  2292.             directory);
  2293.         final List<Path> list = visitor.getFileList();
  2294.         list.addAll(visitor.getDirList());
  2295.         return toList(list.stream().map(Path::toFile));
  2296.     }

  2297.     /**
  2298.      * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure.
  2299.      * <p>
  2300.      * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is
  2301.      * null, nothing happens.
  2302.      * </p>
  2303.      *
  2304.      * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens.
  2305.      * @return the given directory.
  2306.      * @throws IOException       if the directory was not created along with all its parent directories.
  2307.      * @throws IOException       if the given file object is not a directory.
  2308.      * @throws SecurityException See {@link File#mkdirs()}.
  2309.      * @see File#mkdirs()
  2310.      */
  2311.     private static File mkdirs(final File directory) throws IOException {
  2312.         if (directory != null && !directory.mkdirs() && !directory.isDirectory()) {
  2313.             throw new IOException("Cannot create directory '" + directory + "'.");
  2314.         }
  2315.         return directory;
  2316.     }

  2317.     /**
  2318.      * Moves a directory.
  2319.      * <p>
  2320.      * When the destination directory is on another file system, do a "copy and delete".
  2321.      * </p>
  2322.      *
  2323.      * @param srcDir the directory to be moved.
  2324.      * @param destDir the destination directory.
  2325.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  2326.      * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory
  2327.      * @throws FileNotFoundException if the source does not exist.
  2328.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  2329.      * @since 1.4
  2330.      */
  2331.     public static void moveDirectory(final File srcDir, final File destDir) throws IOException {
  2332.         Objects.requireNonNull(destDir, "destination");
  2333.         requireDirectoryExists(srcDir, "srcDir");
  2334.         requireAbsent(destDir, "destDir");
  2335.         if (!srcDir.renameTo(destDir)) {
  2336.             if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) {
  2337.                 throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir);
  2338.             }
  2339.             copyDirectory(srcDir, destDir);
  2340.             deleteDirectory(srcDir);
  2341.             if (srcDir.exists()) {
  2342.                 throw new IOException("Failed to delete original directory '" + srcDir +
  2343.                         "' after copy to '" + destDir + "'");
  2344.             }
  2345.         }
  2346.     }

  2347.     /**
  2348.      * Moves a directory to another directory.
  2349.      * <p>
  2350.      * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
  2351.      * </p>
  2352.      *
  2353.      * @param source the directory to be moved.
  2354.      * @param destDir the destination file.
  2355.      * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an
  2356.      *        IOException.
  2357.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  2358.      * @throws IllegalArgumentException if the source or destination is invalid.
  2359.      * @throws FileNotFoundException if the source does not exist.
  2360.      * @throws IOException if the directory was not created along with all its parent directories, if enabled.
  2361.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  2362.      * @throws SecurityException See {@link File#mkdirs()}.
  2363.      * @since 1.4
  2364.      */
  2365.     public static void moveDirectoryToDirectory(final File source, final File destDir, final boolean createDestDir) throws IOException {
  2366.         validateMoveParameters(source, destDir);
  2367.         if (!destDir.isDirectory()) {
  2368.             if (destDir.exists()) {
  2369.                 throw new IOException("Destination '" + destDir + "' is not a directory");
  2370.             }
  2371.             if (!createDestDir) {
  2372.                 throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + false + "]");
  2373.             }
  2374.             mkdirs(destDir);
  2375.         }
  2376.         moveDirectory(source, new File(destDir, source.getName()));
  2377.     }

  2378.     /**
  2379.      * Moves a file preserving attributes.
  2380.      * <p>
  2381.      * Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}.
  2382.      * </p>
  2383.      * <p>
  2384.      * When the destination file is on another file system, do a "copy and delete".
  2385.      * </p>
  2386.      *
  2387.      * @param srcFile the file to be moved.
  2388.      * @param destFile the destination file.
  2389.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  2390.      * @throws FileExistsException if the destination file exists.
  2391.      * @throws FileNotFoundException if the source file does not exist.
  2392.      * @throws IllegalArgumentException if {@code srcFile} is a directory
  2393.      * @throws IOException if an error occurs.
  2394.      * @since 1.4
  2395.      */
  2396.     public static void moveFile(final File srcFile, final File destFile) throws IOException {
  2397.         moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES);
  2398.     }

  2399.     /**
  2400.      * Moves a file.
  2401.      * <p>
  2402.      * When the destination file is on another file system, do a "copy and delete".
  2403.      * </p>
  2404.      *
  2405.      * @param srcFile the file to be moved.
  2406.      * @param destFile the destination file.
  2407.      * @param copyOptions Copy options.
  2408.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  2409.      * @throws FileExistsException if the destination file exists.
  2410.      * @throws FileNotFoundException if the source file does not exist.
  2411.      * @throws IllegalArgumentException if {@code srcFile} is a directory
  2412.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  2413.      * @since 2.9.0
  2414.      */
  2415.     public static void moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException {
  2416.         Objects.requireNonNull(destFile, "destination");
  2417.         checkFileExists(srcFile, "srcFile");
  2418.         requireAbsent(destFile, "destFile");
  2419.         final boolean rename = srcFile.renameTo(destFile);
  2420.         if (!rename) {
  2421.             // Don't interfere with file date on move, handled by StandardCopyOption.COPY_ATTRIBUTES
  2422.             copyFile(srcFile, destFile, false, copyOptions);
  2423.             if (!srcFile.delete()) {
  2424.                 deleteQuietly(destFile);
  2425.                 throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'");
  2426.             }
  2427.         }
  2428.     }

  2429.     /**
  2430.      * Moves a file into a directory.
  2431.      * <p>
  2432.      * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
  2433.      * </p>
  2434.      *
  2435.      * @param srcFile the file to be moved.
  2436.      * @param destDir the directory to move the file into
  2437.      * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an
  2438.      *        IOException if the destination directory does not already exist.
  2439.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  2440.      * @throws FileExistsException if the destination file exists.
  2441.      * @throws FileNotFoundException if the source file does not exist.
  2442.      * @throws IOException if source or destination is invalid.
  2443.      * @throws IOException if the directory was not created along with all its parent directories, if enabled.
  2444.      * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
  2445.      * @throws SecurityException See {@link File#mkdirs()}.
  2446.      * @throws IllegalArgumentException if {@code destDir} exists but is not a directory
  2447.      * @since 1.4
  2448.      */
  2449.     public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException {
  2450.         validateMoveParameters(srcFile, destDir);
  2451.         if (!destDir.exists() && createDestDir) {
  2452.             mkdirs(destDir);
  2453.         }
  2454.         requireDirectoryExists(destDir, "destDir");
  2455.         moveFile(srcFile, new File(destDir, srcFile.getName()));
  2456.     }

  2457.     /**
  2458.      * Moves a file or directory into a destination directory.
  2459.      * <p>
  2460.      * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
  2461.      * </p>
  2462.      * <p>
  2463.      * When the destination is on another file system, do a "copy and delete".
  2464.      * </p>
  2465.      *
  2466.      * @param src           the file or directory to be moved.
  2467.      * @param destDir       the destination directory.
  2468.      * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an
  2469.      *        IOException if the destination directory does not already exist.
  2470.      * @throws NullPointerException  if any of the given {@link File}s are {@code null}.
  2471.      * @throws FileExistsException   if the directory or file exists in the destination directory.
  2472.      * @throws FileNotFoundException if the source file does not exist.
  2473.      * @throws IOException           if source or destination is invalid.
  2474.      * @throws IOException           if an error occurs or setting the last-modified time didn't succeed.
  2475.      * @since 1.4
  2476.      */
  2477.     public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException {
  2478.         validateMoveParameters(src, destDir);
  2479.         if (src.isDirectory()) {
  2480.             moveDirectoryToDirectory(src, destDir, createDestDir);
  2481.         } else {
  2482.             moveFileToDirectory(src, destDir, createDestDir);
  2483.         }
  2484.     }

  2485.     /**
  2486.      * Creates a new OutputStream by opening or creating a file, returning an output stream that may be used to write bytes
  2487.      * to the file.
  2488.      *
  2489.      * @param append Whether or not to append.
  2490.      * @param file the File.
  2491.      * @return a new OutputStream.
  2492.      * @throws IOException if an I/O error occurs.
  2493.      * @see PathUtils#newOutputStream(Path, boolean)
  2494.      * @since 2.12.0
  2495.      */
  2496.     public static OutputStream newOutputStream(final File file, final boolean append) throws IOException {
  2497.         return PathUtils.newOutputStream(Objects.requireNonNull(file, PROTOCOL_FILE).toPath(), append);
  2498.     }

  2499.     /**
  2500.      * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling
  2501.      * {@code new FileInputStream(file)}.
  2502.      * <p>
  2503.      * At the end of the method either the stream will be successfully opened, or an exception will have been thrown.
  2504.      * </p>
  2505.      * <p>
  2506.      * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a
  2507.      * directory. An exception is thrown if the file exists but cannot be read.
  2508.      * </p>
  2509.      *
  2510.      * @param file the file to open for input, must not be {@code null}
  2511.      * @return a new {@link FileInputStream} for the specified file
  2512.      * @throws NullPointerException if file is {@code null}.
  2513.      * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
  2514.      *         other reason cannot be opened for reading.
  2515.      * @throws IOException See FileNotFoundException above, FileNotFoundException is a subclass of IOException.
  2516.      * @since 1.3
  2517.      */
  2518.     public static FileInputStream openInputStream(final File file) throws IOException {
  2519.         Objects.requireNonNull(file, PROTOCOL_FILE);
  2520.         return new FileInputStream(file);
  2521.     }

  2522.     /**
  2523.      * Opens a {@link FileOutputStream} for the specified file, checking and
  2524.      * creating the parent directory if it does not exist.
  2525.      * <p>
  2526.      * At the end of the method either the stream will be successfully opened,
  2527.      * or an exception will have been thrown.
  2528.      * </p>
  2529.      * <p>
  2530.      * The parent directory will be created if it does not exist.
  2531.      * The file will be created if it does not exist.
  2532.      * An exception is thrown if the file object exists but is a directory.
  2533.      * An exception is thrown if the file exists but cannot be written to.
  2534.      * An exception is thrown if the parent directory cannot be created.
  2535.      * </p>
  2536.      *
  2537.      * @param file the file to open for output, must not be {@code null}
  2538.      * @return a new {@link FileOutputStream} for the specified file
  2539.      * @throws NullPointerException if the file object is {@code null}.
  2540.      * @throws IllegalArgumentException if the file object is a directory
  2541.      * @throws IllegalArgumentException if the file is not writable.
  2542.      * @throws IOException if the directories could not be created.
  2543.      * @since 1.3
  2544.      */
  2545.     public static FileOutputStream openOutputStream(final File file) throws IOException {
  2546.         return openOutputStream(file, false);
  2547.     }

  2548.     /**
  2549.      * Opens a {@link FileOutputStream} for the specified file, checking and
  2550.      * creating the parent directory if it does not exist.
  2551.      * <p>
  2552.      * At the end of the method either the stream will be successfully opened,
  2553.      * or an exception will have been thrown.
  2554.      * </p>
  2555.      * <p>
  2556.      * The parent directory will be created if it does not exist.
  2557.      * The file will be created if it does not exist.
  2558.      * An exception is thrown if the file object exists but is a directory.
  2559.      * An exception is thrown if the file exists but cannot be written to.
  2560.      * An exception is thrown if the parent directory cannot be created.
  2561.      * </p>
  2562.      *
  2563.      * @param file   the file to open for output, must not be {@code null}
  2564.      * @param append if {@code true}, then bytes will be added to the
  2565.      *               end of the file rather than overwriting
  2566.      * @return a new {@link FileOutputStream} for the specified file
  2567.      * @throws NullPointerException if the file object is {@code null}.
  2568.      * @throws IllegalArgumentException if the file object is a directory
  2569.      * @throws IOException if the directories could not be created, or the file is not writable
  2570.      * @since 2.1
  2571.      */
  2572.     public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {
  2573.         Objects.requireNonNull(file, PROTOCOL_FILE);
  2574.         if (file.exists()) {
  2575.             checkIsFile(file, PROTOCOL_FILE);
  2576.         } else {
  2577.             createParentDirectories(file);
  2578.         }
  2579.         return new FileOutputStream(file, append);
  2580.     }

  2581.     /**
  2582.      * Reads the contents of a file into a byte array.
  2583.      * The file is always closed.
  2584.      *
  2585.      * @param file the file to read, must not be {@code null}
  2586.      * @return the file contents, never {@code null}
  2587.      * @throws NullPointerException if file is {@code null}.
  2588.      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
  2589.      *         regular file, or for some other reason why the file cannot be opened for reading.
  2590.      * @since 1.1
  2591.      */
  2592.     public static byte[] readFileToByteArray(final File file) throws IOException {
  2593.         Objects.requireNonNull(file, PROTOCOL_FILE);
  2594.         return Files.readAllBytes(file.toPath());
  2595.     }

  2596.     /**
  2597.      * Reads the contents of a file into a String using the virtual machine's {@link Charset#defaultCharset() default charset}. The
  2598.      * file is always closed.
  2599.      *
  2600.      * @param file the file to read, must not be {@code null}
  2601.      * @return the file contents, never {@code null}
  2602.      * @throws NullPointerException if file is {@code null}.
  2603.      * @throws IOException          if an I/O error occurs, including when the file does not exist, is a directory rather than a regular file, or for some other
  2604.      *                              reason why the file cannot be opened for reading.
  2605.      * @since 1.3.1
  2606.      * @deprecated Use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding)
  2607.      */
  2608.     @Deprecated
  2609.     public static String readFileToString(final File file) throws IOException {
  2610.         return readFileToString(file, Charset.defaultCharset());
  2611.     }

  2612.     /**
  2613.      * Reads the contents of a file into a String.
  2614.      * The file is always closed.
  2615.      *
  2616.      * @param file     the file to read, must not be {@code null}
  2617.      * @param charsetName the name of the requested charset, {@code null} means platform default
  2618.      * @return the file contents, never {@code null}
  2619.      * @throws NullPointerException if file is {@code null}.
  2620.      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
  2621.      *         regular file, or for some other reason why the file cannot be opened for reading.
  2622.      * @since 2.3
  2623.      */
  2624.     public static String readFileToString(final File file, final Charset charsetName) throws IOException {
  2625.         return IOUtils.toString(() -> Files.newInputStream(file.toPath()), Charsets.toCharset(charsetName));
  2626.     }

  2627.     /**
  2628.      * Reads the contents of a file into a String. The file is always closed.
  2629.      *
  2630.      * @param file     the file to read, must not be {@code null}
  2631.      * @param charsetName the name of the requested charset, {@code null} means platform default
  2632.      * @return the file contents, never {@code null}
  2633.      * @throws NullPointerException if file is {@code null}.
  2634.      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
  2635.      *         regular file, or for some other reason why the file cannot be opened for reading.
  2636.      * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable.
  2637.      * @since 2.3
  2638.      */
  2639.     public static String readFileToString(final File file, final String charsetName) throws IOException {
  2640.         return readFileToString(file, Charsets.toCharset(charsetName));
  2641.     }

  2642.     /**
  2643.      * Reads the contents of a file line by line to a List of Strings using the virtual machine's {@link Charset#defaultCharset() default charset}.
  2644.      * The file is always closed.
  2645.      *
  2646.      * @param file the file to read, must not be {@code null}
  2647.      * @return the list of Strings representing each line in the file, never {@code null}
  2648.      * @throws NullPointerException if file is {@code null}.
  2649.      * @throws IOException          if an I/O error occurs, including when the file does not exist, is a directory rather than a regular file, or for some other
  2650.      *                              reason why the file cannot be opened for reading.
  2651.      * @since 1.3
  2652.      * @deprecated Use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding)
  2653.      */
  2654.     @Deprecated
  2655.     public static List<String> readLines(final File file) throws IOException {
  2656.         return readLines(file, Charset.defaultCharset());
  2657.     }

  2658.     /**
  2659.      * Reads the contents of a file line by line to a List of Strings.
  2660.      * The file is always closed.
  2661.      *
  2662.      * @param file     the file to read, must not be {@code null}
  2663.      * @param charset the charset to use, {@code null} means platform default
  2664.      * @return the list of Strings representing each line in the file, never {@code null}
  2665.      * @throws NullPointerException if file is {@code null}.
  2666.      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
  2667.      *         regular file, or for some other reason why the file cannot be opened for reading.
  2668.      * @since 2.3
  2669.      */
  2670.     public static List<String> readLines(final File file, final Charset charset) throws IOException {
  2671.         return Files.readAllLines(file.toPath(), charset);
  2672.     }

  2673.     /**
  2674.      * Reads the contents of a file line by line to a List of Strings. The file is always closed.
  2675.      *
  2676.      * @param file     the file to read, must not be {@code null}
  2677.      * @param charsetName the name of the requested charset, {@code null} means platform default
  2678.      * @return the list of Strings representing each line in the file, never {@code null}
  2679.      * @throws NullPointerException if file is {@code null}.
  2680.      * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
  2681.      *         regular file, or for some other reason why the file cannot be opened for reading.
  2682.      * @throws java.nio.charset.UnsupportedCharsetException 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.     private static void requireAbsent(final File file, final String name) throws FileExistsException {
  2689.         if (file.exists()) {
  2690.             throw new FileExistsException(String.format("File element in parameter '%s' already exists: '%s'", name, file));
  2691.         }
  2692.     }

  2693.     /**
  2694.      * Throws IllegalArgumentException if the given files' canonical representations are equal.
  2695.      *
  2696.      * @param file1 The first file to compare.
  2697.      * @param file2 The second file to compare.
  2698.      * @throws IOException if an I/O error occurs.
  2699.      * @throws IllegalArgumentException if the given files' canonical representations are equal.
  2700.      */
  2701.     private static void requireCanonicalPathsNotEquals(final File file1, final File file2) throws IOException {
  2702.         final String canonicalPath = file1.getCanonicalPath();
  2703.         if (canonicalPath.equals(file2.getCanonicalPath())) {
  2704.             throw new IllegalArgumentException(String
  2705.                 .format("File canonical paths are equal: '%s' (file1='%s', file2='%s')", canonicalPath, file1, file2));
  2706.         }
  2707.     }

  2708.     /**
  2709.      * Requires that the given {@link File} exists and is a directory.
  2710.      *
  2711.      * @param directory The {@link File} to check.
  2712.      * @param name The parameter name to use in the exception message in case of null input or if the file is not a directory.
  2713.      * @throws NullPointerException if the given {@link File} is {@code null}.
  2714.      * @throws FileNotFoundException if the given {@link File} does not exist
  2715.      * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
  2716.      */
  2717.     private static void requireDirectoryExists(final File directory, final String name) throws FileNotFoundException {
  2718.         Objects.requireNonNull(directory, name);
  2719.         if (!directory.isDirectory()) {
  2720.             if (directory.exists()) {
  2721.                 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'");
  2722.             }
  2723.             throw new FileNotFoundException("Directory '" + directory + "' does not exist.");
  2724.         }
  2725.     }

  2726.     /**
  2727.      * Requires that the given {@link File} is a directory if it exists.
  2728.      *
  2729.      * @param directory The {@link File} to check.
  2730.      * @param name The parameter name to use in the exception message in case of null input.
  2731.      * @throws NullPointerException if the given {@link File} is {@code null}.
  2732.      * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
  2733.      */
  2734.     private static void requireDirectoryIfExists(final File directory, final String name) {
  2735.         Objects.requireNonNull(directory, name);
  2736.         if (directory.exists() && !directory.isDirectory()) {
  2737.             throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'");
  2738.         }
  2739.     }

  2740.     /**
  2741.      * Sets file lastModifiedTime, lastAccessTime and creationTime to match source file
  2742.      *
  2743.      * @param sourceFile The source file to query.
  2744.      * @param targetFile The target file or directory to set.
  2745.      * @return {@code true} if and only if the operation succeeded;
  2746.      *          {@code false} otherwise
  2747.      * @throws NullPointerException if sourceFile is {@code null}.
  2748.      * @throws NullPointerException if targetFile is {@code null}.
  2749.      */
  2750.     private static boolean setTimes(final File sourceFile, final File targetFile) {
  2751.         Objects.requireNonNull(sourceFile, "sourceFile");
  2752.         Objects.requireNonNull(targetFile, "targetFile");
  2753.         try {
  2754.             // Set creation, modified, last accessed to match source file
  2755.             final BasicFileAttributes srcAttr = Files.readAttributes(sourceFile.toPath(), BasicFileAttributes.class);
  2756.             final BasicFileAttributeView destAttrView = Files.getFileAttributeView(targetFile.toPath(), BasicFileAttributeView.class);
  2757.             // null guards are not needed; BasicFileAttributes.setTimes(...) is null safe
  2758.             destAttrView.setTimes(srcAttr.lastModifiedTime(), srcAttr.lastAccessTime(), srcAttr.creationTime());
  2759.             return true;
  2760.         } catch (final IOException ignored) {
  2761.             // Fallback: Only set modified time to match source file
  2762.             return targetFile.setLastModified(sourceFile.lastModified());
  2763.         }

  2764.         // TODO: (Help!) Determine historically why setLastModified(File, File) needed PathUtils.setLastModifiedTime() if
  2765.         //  sourceFile.isFile() was true, but needed setLastModifiedTime(File, long) if sourceFile.isFile() was false
  2766.     }

  2767.     /**
  2768.      * Returns the size of the specified file or directory. If the provided
  2769.      * {@link File} is a regular file, then the file's length is returned.
  2770.      * If the argument is a directory, then the size of the directory is
  2771.      * calculated recursively. If a directory or subdirectory is security
  2772.      * restricted, its size will not be included.
  2773.      * <p>
  2774.      * Note that overflow is not detected, and the return value may be negative if
  2775.      * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative
  2776.      * method that does not overflow.
  2777.      * </p>
  2778.      *
  2779.      * @param file the regular file or directory to return the size
  2780.      *             of (must not be {@code null}).
  2781.      *
  2782.      * @return the length of the file, or recursive size of the directory,
  2783.      * provided (in bytes).
  2784.      *
  2785.      * @throws NullPointerException     if the file is {@code null}.
  2786.      * @throws IllegalArgumentException if the file does not exist.
  2787.      * @throws UncheckedIOException if an IO error occurs.
  2788.      * @since 2.0
  2789.      */
  2790.     public static long sizeOf(final File file) {
  2791.         return Uncheck.getAsLong(() -> PathUtils.sizeOf(file.toPath()));
  2792.     }

  2793.     /**
  2794.      * Returns the size of the specified file or directory. If the provided
  2795.      * {@link File} is a regular file, then the file's length is returned.
  2796.      * If the argument is a directory, then the size of the directory is
  2797.      * calculated recursively. If a directory or subdirectory is security
  2798.      * restricted, its size will not be included.
  2799.      *
  2800.      * @param file the regular file or directory to return the size
  2801.      *             of (must not be {@code null}).
  2802.      *
  2803.      * @return the length of the file, or recursive size of the directory,
  2804.      * provided (in bytes).
  2805.      *
  2806.      * @throws NullPointerException     if the file is {@code null}.
  2807.      * @throws IllegalArgumentException if the file does not exist.
  2808.      * @throws UncheckedIOException if an IO error occurs.
  2809.      * @since 2.4
  2810.      */
  2811.     public static BigInteger sizeOfAsBigInteger(final File file) {
  2812.         return Uncheck.get(() -> PathUtils.sizeOfAsBigInteger(file.toPath()));
  2813.     }

  2814.     /**
  2815.      * Counts the size of a directory recursively (sum of the length of all files).
  2816.      * <p>
  2817.      * Note that overflow is not detected, and the return value may be negative if
  2818.      * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative
  2819.      * method that does not overflow.
  2820.      * </p>
  2821.      *
  2822.      * @param directory directory to inspect, must not be {@code null}.
  2823.      * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total
  2824.      * is greater than {@link Long#MAX_VALUE}.
  2825.      * @throws IllegalArgumentException if the given {@link File} exists but is not a directory
  2826.      * @throws NullPointerException if the directory is {@code null}.
  2827.      * @throws UncheckedIOException if an IO error occurs.
  2828.      */
  2829.     public static long sizeOfDirectory(final File directory) {
  2830.         try {
  2831.             requireDirectoryExists(directory, "directory");
  2832.         } catch (final FileNotFoundException e) {
  2833.             throw new UncheckedIOException(e);
  2834.         }
  2835.         return Uncheck.getAsLong(() -> PathUtils.sizeOfDirectory(directory.toPath()));
  2836.     }

  2837.     /**
  2838.      * Counts the size of a directory recursively (sum of the length of all files).
  2839.      *
  2840.      * @param directory directory to inspect, must not be {@code null}.
  2841.      * @return size of directory in bytes, 0 if directory is security restricted.
  2842.      * @throws IllegalArgumentException if the given {@link File} exists but is not a directory
  2843.      * @throws NullPointerException if the directory is {@code null}.
  2844.      * @throws UncheckedIOException if an IO error occurs.
  2845.      * @since 2.4
  2846.      */
  2847.     public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) {
  2848.         try {
  2849.             requireDirectoryExists(directory, "directory");
  2850.         } catch (final FileNotFoundException e) {
  2851.             throw new UncheckedIOException(e);
  2852.         }
  2853.         return Uncheck.get(() -> PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath()));
  2854.     }

  2855.     /**
  2856.      * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions.
  2857.      * <p>
  2858.      * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a
  2859.      * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a
  2860.      * closed stream causes a {@link IllegalStateException}.
  2861.      * </p>
  2862.      *
  2863.      * @param directory  the directory to search in
  2864.      * @param recursive  if true all subdirectories are searched as well
  2865.      * @param extensions an array of extensions, for example, {"java","xml"}. If this parameter is {@code null}, all files are returned.
  2866.      * @return a Stream of {@link File} for matching files.
  2867.      * @throws IOException if an I/O error is thrown when accessing the starting file.
  2868.      * @since 2.9.0
  2869.      */
  2870.     public static Stream<File> streamFiles(final File directory, final boolean recursive, final String... extensions) throws IOException {
  2871.         // @formatter:off
  2872.         final IOFileFilter filter = extensions == null
  2873.             ? FileFileFilter.INSTANCE
  2874.             : FileFileFilter.INSTANCE.and(toSuffixFileFilter(extensions));
  2875.         // @formatter:on
  2876.         return PathUtils.walk(directory.toPath(), filter, toMaxDepth(recursive), false, FileVisitOption.FOLLOW_LINKS).map(Path::toFile);
  2877.     }

  2878.     /**
  2879.      * Converts from a {@link URL} to a {@link File}.
  2880.      * <p>
  2881.      * Syntax such as {@code file:///my%20docs/file.txt} will be
  2882.      * correctly decoded to {@code /my docs/file.txt}.
  2883.      * UTF-8 is used to decode percent-encoded octets to characters.
  2884.      * Additionally, malformed percent-encoded octets are handled leniently by
  2885.      * passing them through literally.
  2886.      * </p>
  2887.      *
  2888.      * @param url the file URL to convert, {@code null} returns {@code null}
  2889.      * @return the equivalent {@link File} object, or {@code null}
  2890.      * if the URL's protocol is not {@code file}
  2891.      */
  2892.     public static File toFile(final URL url) {
  2893.         if (url == null || !isFileProtocol(url)) {
  2894.             return null;
  2895.         }
  2896.         final String fileName = url.getFile().replace('/', File.separatorChar);
  2897.         return new File(decodeUrl(fileName));
  2898.     }

  2899.     /**
  2900.      * Converts each of an array of {@link URL} to a {@link File}.
  2901.      * <p>
  2902.      * Returns an array of the same size as the input.
  2903.      * If the input is {@code null}, an empty array is returned.
  2904.      * If the input contains {@code null}, the output array contains {@code null} at the same
  2905.      * index.
  2906.      * </p>
  2907.      * <p>
  2908.      * This method will decode the URL.
  2909.      * Syntax such as {@code file:///my%20docs/file.txt} will be
  2910.      * correctly decoded to {@code /my docs/file.txt}.
  2911.      * </p>
  2912.      *
  2913.      * @param urls the file URLs to convert, {@code null} returns empty array
  2914.      * @return a non-{@code null} array of Files matching the input, with a {@code null} item
  2915.      * if there was a {@code null} at that index in the input array
  2916.      * @throws IllegalArgumentException if any file is not a URL file
  2917.      * @throws IllegalArgumentException if any file is incorrectly encoded
  2918.      * @since 1.1
  2919.      */
  2920.     public static File[] toFiles(final URL... urls) {
  2921.         if (IOUtils.length(urls) == 0) {
  2922.             return EMPTY_FILE_ARRAY;
  2923.         }
  2924.         final File[] files = new File[urls.length];
  2925.         for (int i = 0; i < urls.length; i++) {
  2926.             final URL url = urls[i];
  2927.             if (url != null) {
  2928.                 if (!isFileProtocol(url)) {
  2929.                     throw new IllegalArgumentException("Can only convert file URL to a File: " + url);
  2930.                 }
  2931.                 files[i] = toFile(url);
  2932.             }
  2933.         }
  2934.         return files;
  2935.     }

  2936.     /**
  2937.      * Consumes all of the given stream.
  2938.      * <p>
  2939.      * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}.
  2940.      * </p>
  2941.      *
  2942.      * @param stream The stream to consume.
  2943.      * @return a new List.
  2944.      */
  2945.     private static List<File> toList(final Stream<File> stream) {
  2946.         return stream.collect(Collectors.toList());
  2947.     }

  2948.     /**
  2949.      * Converts whether or not to recurse into a recursion max depth.
  2950.      *
  2951.      * @param recursive whether or not to recurse
  2952.      * @return the recursion depth
  2953.      */
  2954.     private static int toMaxDepth(final boolean recursive) {
  2955.         return recursive ? Integer.MAX_VALUE : 1;
  2956.     }

  2957.     /**
  2958.      * Converts an array of file extensions to suffixes.
  2959.      *
  2960.      * @param extensions an array of extensions. Format: {"java", "xml"}
  2961.      * @return an array of suffixes. Format: {".java", ".xml"}
  2962.      * @throws NullPointerException if the parameter is null
  2963.      */
  2964.     private static String[] toSuffixes(final String... extensions) {
  2965.         return Stream.of(Objects.requireNonNull(extensions, "extensions")).map(s -> s.charAt(0) == '.' ? s : "." + s).toArray(String[]::new);
  2966.     }

  2967.     private static SuffixFileFilter toSuffixFileFilter(final String... extensions) {
  2968.         return new SuffixFileFilter(toSuffixes(extensions));
  2969.     }

  2970.     /**
  2971.      * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just
  2972.      * updates the file's modified time. This method throws an IOException if the last modified date
  2973.      * of the file cannot be set. It creates parent directories if they do not exist.
  2974.      *
  2975.      * @param file the File to touch.
  2976.      * @throws NullPointerException if the parameter is {@code null}.
  2977.      * @throws IOException if setting the last-modified time failed or an I/O problem occurs.
  2978.      */
  2979.     public static void touch(final File file) throws IOException {
  2980.         PathUtils.touch(Objects.requireNonNull(file, PROTOCOL_FILE).toPath());
  2981.     }

  2982.     /**
  2983.      * Converts each element of an array of {@link File} to a {@link URL}.
  2984.      * <p>
  2985.      * Returns an array of the same size as the input.
  2986.      * </p>
  2987.      *
  2988.      * @param files the files to convert, must not be {@code null}
  2989.      * @return an array of URLs matching the input
  2990.      * @throws IOException          if a file cannot be converted
  2991.      * @throws NullPointerException if any argument is null
  2992.      */
  2993.     public static URL[] toURLs(final File... files) throws IOException {
  2994.         Objects.requireNonNull(files, "files");
  2995.         final URL[] urls = new URL[files.length];
  2996.         for (int i = 0; i < urls.length; i++) {
  2997.             urls[i] = files[i].toURI().toURL();
  2998.         }
  2999.         return urls;
  3000.     }

  3001.     /**
  3002.      * Validates the given arguments.
  3003.      * <ul>
  3004.      * <li>Throws {@link NullPointerException} if {@code source} is null</li>
  3005.      * <li>Throws {@link NullPointerException} if {@code destination} is null</li>
  3006.      * <li>Throws {@link FileNotFoundException} if {@code source} does not exist</li>
  3007.      * </ul>
  3008.      *
  3009.      * @param source      the file or directory to be moved.
  3010.      * @param destination the destination file or directory.
  3011.      * @throws NullPointerException if any of the given {@link File}s are {@code null}.
  3012.      * @throws FileNotFoundException if the source file does not exist.
  3013.      */
  3014.     private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException {
  3015.         Objects.requireNonNull(source, "source");
  3016.         Objects.requireNonNull(destination, "destination");
  3017.         if (!source.exists()) {
  3018.             throw new FileNotFoundException("Source '" + source + "' does not exist");
  3019.         }
  3020.     }

  3021.     /**
  3022.      * Waits for the file system to detect a file's presence, with a timeout.
  3023.      * <p>
  3024.      * This method repeatedly tests {@link Files#exists(Path, LinkOption...)} until it returns
  3025.      * true up to the maximum time specified in seconds.
  3026.      * </p>
  3027.      *
  3028.      * @param file    the file to check, must not be {@code null}
  3029.      * @param seconds the maximum time in seconds to wait
  3030.      * @return true if file exists
  3031.      * @throws NullPointerException if the file is {@code null}
  3032.      */
  3033.     public static boolean waitFor(final File file, final int seconds) {
  3034.         Objects.requireNonNull(file, PROTOCOL_FILE);
  3035.         return PathUtils.waitFor(file.toPath(), Duration.ofSeconds(seconds), PathUtils.EMPTY_LINK_OPTION_ARRAY);
  3036.     }

  3037.     /**
  3038.      * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}.
  3039.      *
  3040.      * @param file the file to write
  3041.      * @param data the content to write to the file
  3042.      * @throws IOException in case of an I/O error
  3043.      * @since 2.0
  3044.      * @deprecated Use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding)
  3045.      */
  3046.     @Deprecated
  3047.     public static void write(final File file, final CharSequence data) throws IOException {
  3048.         write(file, data, Charset.defaultCharset(), false);
  3049.     }

  3050.     /**
  3051.      * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}.
  3052.      *
  3053.      * @param file   the file to write
  3054.      * @param data   the content to write to the file
  3055.      * @param append if {@code true}, then the data will be added to the end of the file rather than overwriting
  3056.      * @throws IOException in case of an I/O error
  3057.      * @since 2.1
  3058.      * @deprecated Use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding)
  3059.      */
  3060.     @Deprecated
  3061.     public static void write(final File file, final CharSequence data, final boolean append) throws IOException {
  3062.         write(file, data, Charset.defaultCharset(), append);
  3063.     }

  3064.     /**
  3065.      * Writes a CharSequence to a file creating the file if it does not exist.
  3066.      *
  3067.      * @param file     the file to write
  3068.      * @param data     the content to write to the file
  3069.      * @param charset the name of the requested charset, {@code null} means platform default
  3070.      * @throws IOException in case of an I/O error
  3071.      * @since 2.3
  3072.      */
  3073.     public static void write(final File file, final CharSequence data, final Charset charset) throws IOException {
  3074.         write(file, data, charset, false);
  3075.     }

  3076.     /**
  3077.      * Writes a CharSequence to a file creating the file if it does not exist.
  3078.      *
  3079.      * @param file     the file to write
  3080.      * @param data     the content to write to the file
  3081.      * @param charset the charset to use, {@code null} means platform default
  3082.      * @param append   if {@code true}, then the data will be added to the
  3083.      *                 end of the file rather than overwriting
  3084.      * @throws IOException in case of an I/O error
  3085.      * @since 2.3
  3086.      */
  3087.     public static void write(final File file, final CharSequence data, final Charset charset, final boolean append) throws IOException {
  3088.         writeStringToFile(file, Objects.toString(data, null), charset, append);
  3089.     }

  3090.     /**
  3091.      * Writes a CharSequence to a file creating the file if it does not exist.
  3092.      *
  3093.      * @param file     the file to write
  3094.      * @param data     the content to write to the file
  3095.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3096.      * @throws IOException                          in case of an I/O error
  3097.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3098.      * @since 2.0
  3099.      */
  3100.     public static void write(final File file, final CharSequence data, final String charsetName) throws IOException {
  3101.         write(file, data, charsetName, false);
  3102.     }

  3103.     /**
  3104.      * Writes a CharSequence to a file creating the file if it does not exist.
  3105.      *
  3106.      * @param file     the file to write
  3107.      * @param data     the content to write to the file
  3108.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3109.      * @param append   if {@code true}, then the data will be added to the
  3110.      *                 end of the file rather than overwriting
  3111.      * @throws IOException                 in case of an I/O error
  3112.      * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
  3113.      * @since 2.1
  3114.      */
  3115.     public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) throws IOException {
  3116.         write(file, data, Charsets.toCharset(charsetName), append);
  3117.     }

  3118.     // Must be called with a directory

  3119.     /**
  3120.      * Writes a byte array to a file creating the file if it does not exist.
  3121.      * The parent directories of the file will be created if they do not exist.
  3122.      *
  3123.      * @param file the file to write to
  3124.      * @param data the content to write to the file
  3125.      * @throws IOException in case of an I/O error
  3126.      * @since 1.1
  3127.      */
  3128.     public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException {
  3129.         writeByteArrayToFile(file, data, false);
  3130.     }

  3131.     /**
  3132.      * Writes a byte array to a file creating the file if it does not exist.
  3133.      *
  3134.      * @param file   the file to write to
  3135.      * @param data   the content to write to the file
  3136.      * @param append if {@code true}, then bytes will be added to the
  3137.      *               end of the file rather than overwriting
  3138.      * @throws IOException in case of an I/O error
  3139.      * @since 2.1
  3140.      */
  3141.     public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException {
  3142.         writeByteArrayToFile(file, data, 0, data.length, append);
  3143.     }

  3144.     /**
  3145.      * Writes {@code len} bytes from the specified byte array starting
  3146.      * at offset {@code off} to a file, creating the file if it does
  3147.      * not exist.
  3148.      *
  3149.      * @param file the file to write to
  3150.      * @param data the content to write to the file
  3151.      * @param off  the start offset in the data
  3152.      * @param len  the number of bytes to write
  3153.      * @throws IOException in case of an I/O error
  3154.      * @since 2.5
  3155.      */
  3156.     public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException {
  3157.         writeByteArrayToFile(file, data, off, len, false);
  3158.     }

  3159.     /**
  3160.      * Writes {@code len} bytes from the specified byte array starting
  3161.      * at offset {@code off} to a file, creating the file if it does
  3162.      * not exist.
  3163.      *
  3164.      * @param file   the file to write to
  3165.      * @param data   the content to write to the file
  3166.      * @param off    the start offset in the data
  3167.      * @param len    the number of bytes to write
  3168.      * @param append if {@code true}, then bytes will be added to the
  3169.      *               end of the file rather than overwriting
  3170.      * @throws IOException in case of an I/O error
  3171.      * @since 2.5
  3172.      */
  3173.     public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException {
  3174.         try (OutputStream out = newOutputStream(file, append)) {
  3175.             out.write(data, off, len);
  3176.         }
  3177.     }

  3178.     /**
  3179.      * Writes the {@code toString()} value of each item in a collection to
  3180.      * the specified {@link File} line by line.
  3181.      * The default VM encoding and the default line ending will be used.
  3182.      *
  3183.      * @param file  the file to write to
  3184.      * @param lines the lines to write, {@code null} entries produce blank lines
  3185.      * @throws IOException in case of an I/O error
  3186.      * @since 1.3
  3187.      */
  3188.     public static void writeLines(final File file, final Collection<?> lines) throws IOException {
  3189.         writeLines(file, null, lines, null, false);
  3190.     }

  3191.     /**
  3192.      * Writes the {@code toString()} value of each item in a collection to
  3193.      * the specified {@link File} line by line.
  3194.      * The default VM encoding and the default line ending will be used.
  3195.      *
  3196.      * @param file   the file to write to
  3197.      * @param lines  the lines to write, {@code null} entries produce blank lines
  3198.      * @param append if {@code true}, then the lines will be added to the
  3199.      *               end of the file rather than overwriting
  3200.      * @throws IOException in case of an I/O error
  3201.      * @since 2.1
  3202.      */
  3203.     public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException {
  3204.         writeLines(file, null, lines, null, append);
  3205.     }

  3206.     /**
  3207.      * Writes the {@code toString()} value of each item in a collection to
  3208.      * the specified {@link File} line by line.
  3209.      * The default VM encoding and the specified line ending will be used.
  3210.      *
  3211.      * @param file       the file to write to
  3212.      * @param lines      the lines to write, {@code null} entries produce blank lines
  3213.      * @param lineEnding the line separator to use, {@code null} is system default
  3214.      * @throws IOException in case of an I/O error
  3215.      * @since 1.3
  3216.      */
  3217.     public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException {
  3218.         writeLines(file, null, lines, lineEnding, false);
  3219.     }

  3220.     /**
  3221.      * Writes the {@code toString()} value of each item in a collection to
  3222.      * the specified {@link File} line by line.
  3223.      * The default VM encoding and the specified line ending will be used.
  3224.      *
  3225.      * @param file       the file to write to
  3226.      * @param lines      the lines to write, {@code null} entries produce blank lines
  3227.      * @param lineEnding the line separator to use, {@code null} is system default
  3228.      * @param append     if {@code true}, then the lines will be added to the
  3229.      *                   end of the file rather than overwriting
  3230.      * @throws IOException in case of an I/O error
  3231.      * @since 2.1
  3232.      */
  3233.     public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException {
  3234.         writeLines(file, null, lines, lineEnding, append);
  3235.     }

  3236.     /**
  3237.      * Writes the {@code toString()} value of each item in a collection to
  3238.      * the specified {@link File} line by line.
  3239.      * The specified character encoding and the default line ending will be used.
  3240.      * The parent directories of the file will be created if they do not exist.
  3241.      *
  3242.      * @param file     the file to write to
  3243.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3244.      * @param lines    the lines to write, {@code null} entries produce blank lines
  3245.      * @throws IOException                          in case of an I/O error
  3246.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3247.      * @since 1.1
  3248.      */
  3249.     public static void writeLines(final File file, final String charsetName, final Collection<?> lines) throws IOException {
  3250.         writeLines(file, charsetName, lines, null, false);
  3251.     }

  3252.     /**
  3253.      * Writes the {@code toString()} value of each item in a collection to
  3254.      * the specified {@link File} line by line, optionally appending.
  3255.      * The specified character encoding and the default line ending will be used.
  3256.      *
  3257.      * @param file     the file to write to
  3258.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3259.      * @param lines    the lines to write, {@code null} entries produce blank lines
  3260.      * @param append   if {@code true}, then the lines will be added to the
  3261.      *                 end of the file rather than overwriting
  3262.      * @throws IOException                          in case of an I/O error
  3263.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3264.      * @since 2.1
  3265.      */
  3266.     public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final boolean append) throws IOException {
  3267.         writeLines(file, charsetName, lines, null, append);
  3268.     }

  3269.     /**
  3270.      * Writes the {@code toString()} value of each item in a collection to
  3271.      * the specified {@link File} line by line.
  3272.      * The specified character encoding and the line ending will be used.
  3273.      * The parent directories of the file will be created if they do not exist.
  3274.      *
  3275.      * @param file       the file to write to
  3276.      * @param charsetName   the name of the requested charset, {@code null} means platform default
  3277.      * @param lines      the lines to write, {@code null} entries produce blank lines
  3278.      * @param lineEnding the line separator to use, {@code null} is system default
  3279.      * @throws IOException                          in case of an I/O error
  3280.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3281.      * @since 1.1
  3282.      */
  3283.     public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding) throws IOException {
  3284.         writeLines(file, charsetName, lines, lineEnding, false);
  3285.     }

  3286.     /**
  3287.      * Writes the {@code toString()} value of each item in a collection to
  3288.      * the specified {@link File} line by line.
  3289.      * The specified character encoding and the line ending will be used.
  3290.      *
  3291.      * @param file       the file to write to
  3292.      * @param charsetName   the name of the requested charset, {@code null} means platform default
  3293.      * @param lines      the lines to write, {@code null} entries produce blank lines
  3294.      * @param lineEnding the line separator to use, {@code null} is system default
  3295.      * @param append     if {@code true}, then the lines will be added to the
  3296.      *                   end of the file rather than overwriting
  3297.      * @throws IOException                          in case of an I/O error
  3298.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3299.      * @since 2.1
  3300.      */
  3301.     public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding, final boolean append)
  3302.         throws IOException {
  3303.         try (OutputStream out = new BufferedOutputStream(newOutputStream(file, append))) {
  3304.             IOUtils.writeLines(lines, lineEnding, out, charsetName);
  3305.         }
  3306.     }

  3307.     /**
  3308.      * Writes a String to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}.
  3309.      *
  3310.      * @param file the file to write
  3311.      * @param data the content to write to the file
  3312.      * @throws IOException in case of an I/O error
  3313.      * @deprecated Use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding)
  3314.      */
  3315.     @Deprecated
  3316.     public static void writeStringToFile(final File file, final String data) throws IOException {
  3317.         writeStringToFile(file, data, Charset.defaultCharset(), false);
  3318.     }

  3319.     /**
  3320.      * Writes a String to a file creating the file if it does not exist using the virtual machine's {@link Charset#defaultCharset() default charset}.
  3321.      *
  3322.      * @param file   the file to write
  3323.      * @param data   the content to write to the file
  3324.      * @param append if {@code true}, then the String will be added to the end of the file rather than overwriting
  3325.      * @throws IOException in case of an I/O error
  3326.      * @since 2.1
  3327.      * @deprecated Use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding)
  3328.      */
  3329.     @Deprecated
  3330.     public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException {
  3331.         writeStringToFile(file, data, Charset.defaultCharset(), append);
  3332.     }

  3333.     /**
  3334.      * Writes a String to a file creating the file if it does not exist.
  3335.      * The parent directories of the file will be created if they do not exist.
  3336.      *
  3337.      * @param file     the file to write
  3338.      * @param data     the content to write to the file
  3339.      * @param charset the charset to use, {@code null} means platform default
  3340.      * @throws IOException                          in case of an I/O error
  3341.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3342.      * @since 2.4
  3343.      */
  3344.     public static void writeStringToFile(final File file, final String data, final Charset charset) throws IOException {
  3345.         writeStringToFile(file, data, charset, false);
  3346.     }

  3347.     /**
  3348.      * Writes a String to a file, creating the file if it does not exist.
  3349.      * The parent directories of the file are created if they do not exist.
  3350.      *
  3351.      * @param file     the file to write
  3352.      * @param data     the content to write to the file
  3353.      * @param charset the charset to use, {@code null} means platform default
  3354.      * @param append   if {@code true}, then the String will be added to the
  3355.      *                 end of the file rather than overwriting
  3356.      * @throws IOException in case of an I/O error
  3357.      * @since 2.3
  3358.      */
  3359.     public static void writeStringToFile(final File file, final String data, final Charset charset, final boolean append) throws IOException {
  3360.         try (OutputStream out = newOutputStream(file, append)) {
  3361.             IOUtils.write(data, out, charset);
  3362.         }
  3363.     }

  3364.     /**
  3365.      * Writes a String to a file, creating the file if it does not exist.
  3366.      * The parent directories of the file are created if they do not exist.
  3367.      *
  3368.      * @param file     the file to write
  3369.      * @param data     the content to write to the file
  3370.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3371.      * @throws IOException                          in case of an I/O error
  3372.      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
  3373.      */
  3374.     public static void writeStringToFile(final File file, final String data, final String charsetName) throws IOException {
  3375.         writeStringToFile(file, data, charsetName, false);
  3376.     }

  3377.     /**
  3378.      * Writes a String to a file, creating the file if it does not exist.
  3379.      * The parent directories of the file are created if they do not exist.
  3380.      *
  3381.      * @param file     the file to write
  3382.      * @param data     the content to write to the file
  3383.      * @param charsetName the name of the requested charset, {@code null} means platform default
  3384.      * @param append   if {@code true}, then the String will be added to the
  3385.      *                 end of the file rather than overwriting
  3386.      * @throws IOException                 in case of an I/O error
  3387.      * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
  3388.      * @since 2.1
  3389.      */
  3390.     public static void writeStringToFile(final File file, final String data, final String charsetName, final boolean append) throws IOException {
  3391.         writeStringToFile(file, data, Charsets.toCharset(charsetName), append);
  3392.     }

  3393.     /**
  3394.      * Instances should NOT be constructed in standard programming.
  3395.      *
  3396.      * @deprecated TODO Make private in 3.0.
  3397.      */
  3398.     @Deprecated
  3399.     public FileUtils() { //NOSONAR
  3400.         // empty
  3401.     }

  3402. }