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