/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.io; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.UncheckedIOException; import java.math.BigInteger; import java.net.URL; import java.net.URLConnection; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.CopyOption; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.LinkOption; import java.nio.file.NotDirectoryException; import java.nio.file.Path; import java.nio.file.StandardCopyOption; import java.time.Instant; import java.time.LocalTime; import java.time.ZoneId; import java.time.chrono.ChronoLocalDate; import java.time.chrono.ChronoLocalDateTime; import java.time.chrono.ChronoZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; import java.util.zip.Checksum; import org.apache.commons.io.file.AccumulatorPathVisitor; import org.apache.commons.io.file.Counters; import org.apache.commons.io.file.PathFilter; import org.apache.commons.io.file.PathUtils; import org.apache.commons.io.file.StandardDeleteOption; import org.apache.commons.io.filefilter.FileEqualsFileFilter; import org.apache.commons.io.filefilter.FileFileFilter; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; /** * General file manipulation utilities. *
* Facilities are provided in the following areas: *
** Note that a specific charset should be specified whenever possible. Relying on the platform default means that the * code is Locale-dependent. Only use the default if the files are known to always use the platform default. *
** {@link SecurityException} are not documented in the Javadoc. *
** Origin of code: Excalibur, Alexandria, Commons-Utils *
*/ public class FileUtils { /** * The number of bytes in a kilobyte. */ public static final long ONE_KB = 1024; /** * The number of bytes in a kilobyte. * * @since 2.4 */ public static final BigInteger ONE_KB_BI = BigInteger.valueOf(ONE_KB); /** * The number of bytes in a megabyte. */ public static final long ONE_MB = ONE_KB * ONE_KB; /** * The number of bytes in a megabyte. * * @since 2.4 */ public static final BigInteger ONE_MB_BI = ONE_KB_BI.multiply(ONE_KB_BI); /** * The number of bytes in a gigabyte. */ public static final long ONE_GB = ONE_KB * ONE_MB; /** * The number of bytes in a gigabyte. * * @since 2.4 */ public static final BigInteger ONE_GB_BI = ONE_KB_BI.multiply(ONE_MB_BI); /** * The number of bytes in a terabyte. */ public static final long ONE_TB = ONE_KB * ONE_GB; /** * The number of bytes in a terabyte. * * @since 2.4 */ public static final BigInteger ONE_TB_BI = ONE_KB_BI.multiply(ONE_GB_BI); /** * The number of bytes in a petabyte. */ public static final long ONE_PB = ONE_KB * ONE_TB; /** * The number of bytes in a petabyte. * * @since 2.4 */ public static final BigInteger ONE_PB_BI = ONE_KB_BI.multiply(ONE_TB_BI); /** * The number of bytes in an exabyte. */ public static final long ONE_EB = ONE_KB * ONE_PB; /** * The number of bytes in an exabyte. * * @since 2.4 */ public static final BigInteger ONE_EB_BI = ONE_KB_BI.multiply(ONE_PB_BI); /** * The number of bytes in a zettabyte. */ public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB)); /** * The number of bytes in a yottabyte. */ public static final BigInteger ONE_YB = ONE_KB_BI.multiply(ONE_ZB); /** * An empty array of type {@code File}. */ public static final File[] EMPTY_FILE_ARRAY = {}; /** * Copies the given array and adds StandardCopyOption.COPY_ATTRIBUTES. * * @param copyOptions sorted copy options. * @return a new array. */ private static CopyOption[] addCopyAttributes(final CopyOption... copyOptions) { // Make a copy first since we don't want to sort the call site's version. final CopyOption[] actual = Arrays.copyOf(copyOptions, copyOptions.length + 1); Arrays.sort(actual, 0, copyOptions.length); if (Arrays.binarySearch(copyOptions, 0, copyOptions.length, StandardCopyOption.COPY_ATTRIBUTES) >= 0) { return copyOptions; } actual[actual.length - 1] = StandardCopyOption.COPY_ATTRIBUTES; return actual; } /** * Returns a human-readable version of the file size, where the input represents a specific number of bytes. ** 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 * nearest GB boundary. *
** Similarly for the 1MB and 1KB boundaries. *
* * @param size the number of bytes * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) * @throws NullPointerException if the given {@code BigInteger} is {@code null}. * @see IO-226 - should the rounding be changed? * @since 2.4 */ // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? public static String byteCountToDisplaySize(final BigInteger size) { Objects.requireNonNull(size, "size"); final String displaySize; if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_EB_BI) + " EB"; } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_PB_BI) + " PB"; } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_TB_BI) + " TB"; } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_GB_BI) + " GB"; } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_MB_BI) + " MB"; } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = size.divide(ONE_KB_BI) + " KB"; } else { displaySize = size + " bytes"; } return displaySize; } /** * Returns a human-readable version of the file size, where the input represents a specific number of bytes. ** 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 * nearest GB boundary. *
** Similarly for the 1MB and 1KB boundaries. *
* * @param size the number of bytes * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) * @see IO-226 - should the rounding be changed? */ // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? public static String byteCountToDisplaySize(final long size) { return byteCountToDisplaySize(BigInteger.valueOf(size)); } /** * Computes the checksum of a file using the specified checksum object. Multiple files may be checked using one * {@code Checksum} instance if desired simply by reusing the same checksum object. For example: * ** long checksum = FileUtils.checksum(file, new CRC32()).getValue(); ** * @param file the file to checksum, must not be {@code null} * @param checksum the checksum object to be used, must not be {@code null} * @return the checksum specified, updated with the content of the file * @throws NullPointerException if the given {@code File} is {@code null}. * @throws NullPointerException if the given {@code Checksum} is {@code null}. * @throws IllegalArgumentException if the given {@code File} does not exist or is not a file. * @throws IOException if an IO error occurs reading the file. * @since 1.3 */ public static Checksum checksum(final File file, final Checksum checksum) throws IOException { requireExistsChecked(file, "file"); requireFile(file, "file"); Objects.requireNonNull(checksum, "checksum"); try (InputStream inputStream = new CheckedInputStream(Files.newInputStream(file.toPath()), checksum)) { IOUtils.consume(inputStream); } return checksum; } /** * Computes the checksum of a file using the CRC32 checksum routine. * The value of the checksum is returned. * * @param file the file to checksum, must not be {@code null} * @return the checksum value * @throws NullPointerException if the given {@code File} is {@code null}. * @throws IllegalArgumentException if the given {@code File} does not exist or is not a file. * @throws IOException if an IO error occurs reading the file. * @since 1.3 */ public static long checksumCRC32(final File file) throws IOException { return checksum(file, new CRC32()).getValue(); } /** * Cleans a directory without deleting it. * * @param directory directory to clean * @throws NullPointerException if the given {@code File} is {@code null}. * @throws IllegalArgumentException if directory does not exist or is not a directory. * @throws IOException if an I/O error occurs. * @see #forceDelete(File) */ public static void cleanDirectory(final File directory) throws IOException { final File[] files = listFiles(directory, null); final List
* This method checks to see if the two files are different lengths or if they point to the same file, before * resorting to byte-by-byte comparison of the contents. *
** Code origin: Avalon *
* * @param file1 the first file * @param file2 the second file * @return true if the content of the files are equal or they both don't exist, false otherwise * @throws IllegalArgumentException when an input is not a file. * @throws IOException If an I/O error occurs. * @see org.apache.commons.io.file.PathUtils#fileContentEquals(Path,Path,java.nio.file.LinkOption[],java.nio.file.OpenOption...) */ public static boolean contentEquals(final File file1, final File file2) throws IOException { if (file1 == null && file2 == null) { return true; } if (file1 == null || file2 == null) { return false; } final boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } requireFile(file1, "file1"); requireFile(file2, "file2"); if (file1.length() != file2.length()) { // lengths differ, cannot be equal return false; } if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { // same file return true; } try (InputStream input1 = Files.newInputStream(file1.toPath()); InputStream input2 = Files.newInputStream(file2.toPath())) { return IOUtils.contentEquals(input1, input2); } } /** * Compares the contents of two files to determine if they are equal or not. ** This method checks to see if the two files point to the same file, * before resorting to line-by-line comparison of the contents. *
* * @param file1 the first file * @param file2 the second file * @param charsetName the name of the requested charset. * May be null, in which case the platform default is used * @return true if the content of the files are equal or neither exists, * false otherwise * @throws IllegalArgumentException when an input is not a file. * @throws IOException in case of an I/O error. * @throws UnsupportedCharsetException If the named charset is unavailable (unchecked exception). * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader) * @since 2.2 */ public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName) throws IOException { if (file1 == null && file2 == null) { return true; } if (file1 == null || file2 == null) { return false; } final boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } requireFile(file1, "file1"); requireFile(file2, "file2"); if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { // same file return true; } final Charset charset = Charsets.toCharset(charsetName); try (Reader input1 = new InputStreamReader(Files.newInputStream(file1.toPath()), charset); Reader input2 = new InputStreamReader(Files.newInputStream(file2.toPath()), charset)) { return IOUtils.contentEqualsIgnoreEOL(input1, input2); } } /** * Converts a Collection containing java.io.File instanced into array * representation. This is to account for the difference between * File.listFiles() and FileUtils.listFiles(). * * @param files a Collection containing java.io.File instances * @return an array of java.io.File */ public static File[] convertFileCollectionToFileArray(final Collection* This method copies the specified directory and all its child directories and files to the specified destination. * The destination is the new location and name of the directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: This method tries to preserve the files' last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the * modification operation fails, the methods throws IOException. *
* * @param srcDir an existing directory to copy, must not be {@code null}. * @param destDir the new directory, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 1.1 */ public static void copyDirectory(final File srcDir, final File destDir) throws IOException { copyDirectory(srcDir, destDir, true); } /** * Copies a whole directory to a new location. ** This method copies the contents of the specified source directory to within the specified destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations * will succeed. If the modification operation fails, the methods throws IOException. *
* * @param srcDir an existing directory to copy, must not be {@code null}. * @param destDir the new directory, must not be {@code null}. * @param preserveFileDate true if the file date of the copy should be the same as the original. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 1.1 */ public static void copyDirectory(final File srcDir, final File destDir, final boolean preserveFileDate) throws IOException { copyDirectory(srcDir, destDir, null, preserveFileDate); } /** * Copies a filtered directory to a new location preserving the file dates. ** This method copies the contents of the specified source directory to within the specified destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: This method tries to preserve the files' last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the * modification operation fails, the methods throws IOException. *
* Example: Copy directories only * ** // only copy the directory structure * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY); ** * Example: Copy directories and txt files * *
* // Create a filter for ".txt" files * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); * * // Create a filter for either directories or ".txt" files * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); * * // Copy using the filter * FileUtils.copyDirectory(srcDir, destDir, filter); ** * @param srcDir an existing directory to copy, must not be {@code null}. * @param destDir the new directory, must not be {@code null}. * @param filter the filter to apply, null means copy all directories and files should be the same as the original. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 1.4 */ public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter) throws IOException { copyDirectory(srcDir, destDir, filter, true); } /** * Copies a filtered directory to a new location. *
* This method copies the contents of the specified source directory to within the specified destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations * will succeed. If the modification operation fails, the methods throws IOException. *
* Example: Copy directories only * ** // only copy the directory structure * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false); ** * Example: Copy directories and txt files * *
* // Create a filter for ".txt" files * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); * * // Create a filter for either directories or ".txt" files * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); * * // Copy using the filter * FileUtils.copyDirectory(srcDir, destDir, filter, false); ** * @param srcDir an existing directory to copy, must not be {@code null}. * @param destDir the new directory, must not be {@code null}. * @param filter the filter to apply, null means copy all directories and files. * @param preserveFileDate true if the file date of the copy should be the same as the original. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 1.4 */ public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate) throws IOException { copyDirectory(srcDir, destDir, filter, preserveFileDate, StandardCopyOption.REPLACE_EXISTING); } /** * Copies a filtered directory to a new location. *
* This method copies the contents of the specified source directory to within the specified destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the files' last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that those operations * will succeed. If the modification operation fails, the methods throws IOException. *
* Example: Copy directories only * ** // only copy the directory structure * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false); ** * Example: Copy directories and txt files * *
* // Create a filter for ".txt" files * IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt"); * IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter); * * // Create a filter for either directories or ".txt" files * FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles); * * // Copy using the filter * FileUtils.copyDirectory(srcDir, destDir, filter, false); ** * @param srcDir an existing directory to copy, must not be {@code null} * @param destDir the new directory, must not be {@code null} * @param fileFilter the filter to apply, null means copy all directories and files * @param preserveFileDate true if the file date of the copy should be the same as the original * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 2.8.0 */ public static void copyDirectory(final File srcDir, final File destDir, final FileFilter fileFilter, final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException { requireFileCopy(srcDir, destDir); requireDirectory(srcDir, "srcDir"); requireCanonicalPathsNotEquals(srcDir, destDir); // Cater for destination being directory within the source directory (see IO-141) List
* This method copies the source directory and all its contents to a directory of the same name in the specified * destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: This method tries to preserve the files' last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the * modification operation fails, the methods throws IOException. *
* * @param sourceDir an existing directory to copy, must not be {@code null}. * @param destinationDir the directory to place the copy in, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @since 1.2 */ public static void copyDirectoryToDirectory(final File sourceDir, final File destinationDir) throws IOException { requireDirectoryIfExists(sourceDir, "sourceDir"); requireDirectoryIfExists(destinationDir, "destinationDir"); copyDirectory(sourceDir, new File(destinationDir, sourceDir.getName()), true); } /** * Copies a file to a new location preserving the file date. ** This method copies the contents of the specified source file to the specified destination file. The directory * holding the destination file is created if it does not exist. If the destination file exists, then this method * will overwrite it. *
** Note: This method tries to preserve the file's last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that the operation will succeed. If the * modification operation fails, the methods throws IOException. *
* * @param srcFile an existing file to copy, must not be {@code null}. * @param destFile the new file, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IOException if source or destination is invalid. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @throws IOException if the output file length is not the same as the input file length after the copy completes. * @see #copyFileToDirectory(File, File) * @see #copyFile(File, File, boolean) */ public static void copyFile(final File srcFile, final File destFile) throws IOException { copyFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); } /** * Copies an existing file to a new file location. ** This method copies the contents of the specified source file to the specified destination file. The directory * holding the destination file is created if it does not exist. If the destination file exists, then this method * will overwrite it. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation * will succeed. If the modification operation fails, the methods throws IOException. *
* * @param srcFile an existing file to copy, must not be {@code null}. * @param destFile the new file, must not be {@code null}. * @param preserveFileDate true if the file date of the copy should be the same as the original. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IOException if source or destination is invalid. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @throws IOException if the output file length is not the same as the input file length after the copy completes * @see #copyFile(File, File, boolean, CopyOption...) */ public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException { copyFile(srcFile, destFile, preserveFileDate ? new CopyOption[] {StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING} : new CopyOption[] {StandardCopyOption.REPLACE_EXISTING}); } /** * Copies a file to a new location. ** This method copies the contents of the specified source file to the specified destination file. The directory * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite * it with {@link StandardCopyOption#REPLACE_EXISTING}. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation * will succeed. If the modification operation fails, the methods throws IOException. *
* * @param srcFile an existing file to copy, must not be {@code null}. * @param destFile the new file, must not be {@code null}. * @param preserveFileDate true if the file date of the copy should be the same as the original. * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws FileNotFoundException if the source does not exist. * @throws IllegalArgumentException if source is not a file. * @throws IOException if the output file length is not the same as the input file length after the copy completes. * @throws IOException if an I/O error occurs, or setting the last-modified time didn't succeeded. * @see #copyFileToDirectory(File, File, boolean) * @since 2.8.0 */ public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException { copyFile(srcFile, destFile, preserveFileDate ? addCopyAttributes(copyOptions) : copyOptions); } /** * Copies a file to a new location. ** This method copies the contents of the specified source file to the specified destination file. The directory * holding the destination file is created if it does not exist. If the destination file exists, you can overwrite * it if you use {@link StandardCopyOption#REPLACE_EXISTING}. *
* * @param srcFile an existing file to copy, must not be {@code null}. * @param destFile the new file, must not be {@code null}. * @param copyOptions options specifying how the copy should be done, for example {@link StandardCopyOption}.. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws FileNotFoundException if the source does not exist. * @throws IllegalArgumentException if source is not a file. * @throws IOException if the output file length is not the same as the input file length after the copy completes. * @throws IOException if an I/O error occurs. * @see StandardCopyOption * @since 2.9.0 */ public static void copyFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException { requireFileCopy(srcFile, destFile); requireFile(srcFile, "srcFile"); requireCanonicalPathsNotEquals(srcFile, destFile); createParentDirectories(destFile); requireFileIfExists(destFile, "destFile"); if (destFile.exists()) { requireCanWrite(destFile, "destFile"); } // On Windows, the last modified time is copied by default. Files.copy(srcFile.toPath(), destFile.toPath(), copyOptions); // TODO IO-386: Do we still need this check? requireEqualSizes(srcFile, destFile, srcFile.length(), destFile.length()); } /** * Copies bytes from a {@code File} to an {@code OutputStream}. ** This method buffers the input internally, so there is no need to use a {@code BufferedInputStream}. *
* * @param input the {@code File} to read. * @param output the {@code OutputStream} to write. * @return the number of bytes copied * @throws NullPointerException if the File is {@code null}. * @throws NullPointerException if the OutputStream is {@code null}. * @throws IOException if an I/O error occurs. * @since 2.1 */ public static long copyFile(final File input, final OutputStream output) throws IOException { try (InputStream fis = Files.newInputStream(input.toPath())) { return IOUtils.copyLarge(fis, output); } } /** * Copies a file to a directory preserving the file date. ** This method copies the contents of the specified source file to a file of the same name in the specified * destination directory. The destination directory is created if it does not exist. If the destination file exists, * then this method will overwrite it. *
** Note: This method tries to preserve the file's last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that the operation will succeed. If the * modification operation fails, the methods throws IOException. *
* * @param srcFile an existing file to copy, must not be {@code null}. * @param destDir the directory to place the copy in, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if source or destination is invalid. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @see #copyFile(File, File, boolean) */ public static void copyFileToDirectory(final File srcFile, final File destDir) throws IOException { copyFileToDirectory(srcFile, destDir, true); } /** * Copies a file to a directory optionally preserving the file date. ** This method copies the contents of the specified source file to a file of the same name in the specified * destination directory. The destination directory is created if it does not exist. If the destination file exists, * then this method will overwrite it. *
** Note: Setting {@code preserveFileDate} to {@code true} tries to preserve the file's last * modified date/times using {@link File#setLastModified(long)}, however it is not guaranteed that the operation * will succeed. If the modification operation fails, the methods throws IOException. *
* * @param sourceFile an existing file to copy, must not be {@code null}. * @param destinationDir the directory to place the copy in, must not be {@code null}. * @param preserveFileDate true if the file date of the copy should be the same as the original. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @throws IOException if the output file length is not the same as the input file length after the copy completes. * @see #copyFile(File, File, CopyOption...) * @since 1.3 */ public static void copyFileToDirectory(final File sourceFile, final File destinationDir, final boolean preserveFileDate) throws IOException { Objects.requireNonNull(sourceFile, "sourceFile"); requireDirectoryIfExists(destinationDir, "destinationDir"); copyFile(sourceFile, new File(destinationDir, sourceFile.getName()), preserveFileDate); } /** * Copies bytes from an {@link InputStream} {@code source} to a file * {@code destination}. The directories up to {@code destination} * will be created if they don't already exist. {@code destination} * will be overwritten if it already exists. ** The {@code source} stream is closed. *
** See {@link #copyToFile(InputStream, File)} for a method that does not close the input stream. *
* * @param source the {@code InputStream} to copy bytes from, must not be {@code null}, will be closed * @param destination the non-directory {@code File} to write bytes to * (possibly overwriting), must not be {@code null} * @throws IOException if {@code destination} is a directory * @throws IOException if {@code destination} cannot be written * @throws IOException if {@code destination} needs creating but can't be * @throws IOException if an IO error occurs during copying * @since 2.0 */ public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException { try (InputStream inputStream = source) { copyToFile(inputStream, destination); } } /** * Copies a file or directory to within another directory preserving the file dates. ** This method copies the source file or directory, along all its contents, to a directory of the same name in the * specified destination directory. *
** The destination directory is created if it does not exist. If the destination directory did exist, then this * method merges the source with the destination, with the source taking precedence. *
** Note: This method tries to preserve the files' last modified date/times using * {@link File#setLastModified(long)}, however it is not guaranteed that those operations will succeed. If the * modification operation fails, the methods throws IOException. *
* * @param sourceFile an existing file or directory to copy, must not be {@code null}. * @param destinationDir the directory to place the copy in, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IllegalArgumentException if the source or destination is invalid. * @throws FileNotFoundException if the source does not exist. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @see #copyDirectoryToDirectory(File, File) * @see #copyFileToDirectory(File, File) * @since 2.6 */ public static void copyToDirectory(final File sourceFile, final File destinationDir) throws IOException { Objects.requireNonNull(sourceFile, "sourceFile"); if (sourceFile.isFile()) { copyFileToDirectory(sourceFile, destinationDir); } else if (sourceFile.isDirectory()) { copyDirectoryToDirectory(sourceFile, destinationDir); } else { throw new FileNotFoundException("The source " + sourceFile + " does not exist"); } } /** * Copies a files to a directory preserving each file's date. ** This method copies the contents of the specified source files * to a file of the same name in the specified destination directory. * The destination directory is created if it does not exist. * If the destination file exists, then this method will overwrite it. *
** Note: This method tries to preserve the file's last * modified date/times using {@link File#setLastModified(long)}, however * it is not guaranteed that the operation will succeed. * If the modification operation fails, the methods throws IOException. *
* * @param sourceIterable a existing files to copy, must not be {@code null}. * @param destinationDir the directory to place the copy in, must not be {@code null}. * @throws NullPointerException if any of the given {@code File}s are {@code null}. * @throws IOException if source or destination is invalid. * @throws IOException if an error occurs or setting the last-modified time didn't succeeded. * @see #copyFileToDirectory(File, File) * @since 2.6 */ public static void copyToDirectory(final Iterable* Warning: this method does not set a connection or read timeout and thus * might block forever. Use {@link #copyURLToFile(URL, File, int, int)} * with reasonable timeouts to prevent this. *
* * @param source the {@code URL} to copy bytes from, must not be {@code null} * @param destination the non-directory {@code File} to write bytes to * (possibly overwriting), must not be {@code null} * @throws IOException if {@code source} URL cannot be opened * @throws IOException if {@code destination} is a directory * @throws IOException if {@code destination} cannot be written * @throws IOException if {@code destination} needs creating but can't be * @throws IOException if an IO error occurs during copying */ public static void copyURLToFile(final URL source, final File destination) throws IOException { try (final InputStream stream = source.openStream()) { copyInputStreamToFile(stream, destination); } } /** * Copies bytes from the URL {@code source} to a file {@code destination}. The directories up to * {@code destination} will be created if they don't already exist. {@code destination} will be * overwritten if it already exists. * * @param source the {@code URL} to copy bytes from, must not be {@code null} * @param destination the non-directory {@code File} to write bytes to (possibly overwriting), must not be * {@code null} * @param connectionTimeoutMillis the number of milliseconds until this method will timeout if no connection could * be established to the {@code source} * @param readTimeoutMillis the number of milliseconds until this method will timeout if no data could be read from * the {@code source} * @throws IOException if {@code source} URL cannot be opened * @throws IOException if {@code destination} is a directory * @throws IOException if {@code destination} cannot be written * @throws IOException if {@code destination} needs creating but can't be * @throws IOException if an IO error occurs during copying * @since 2.0 */ public static void copyURLToFile(final URL source, final File destination, final int connectionTimeoutMillis, final int readTimeoutMillis) throws IOException { final URLConnection connection = source.openConnection(); connection.setConnectTimeout(connectionTimeoutMillis); connection.setReadTimeout(readTimeoutMillis); try (final InputStream stream = connection.getInputStream()) { copyInputStreamToFile(stream, destination); } } /** * Creates all parent directories for a File object. * * @param file the File that may need parents, may be null. * @return The parent directory, or {@code null} if the given file does not name a parent * @throws IOException if the directory was not created along with all its parent directories. * @throws IOException if the given file object is not null and not a directory. * @since 2.9.0 */ public static File createParentDirectories(final File file) throws IOException { return mkdirs(getParentFile(file)); } /** * Decodes the specified URL as per RFC 3986, i.e. transforms * percent-encoded octets to characters by decoding with the UTF-8 character * set. This function is primarily intended for usage with * {@link java.net.URL} which unfortunately does not enforce proper URLs. As * such, this method will leniently accept invalid characters or malformed * percent-encoded octets and simply pass them literally through to the * result string. Except for rare edge cases, this will make unencoded URLs * pass through unaltered. * * @param url The URL to decode, may be {@code null}. * @return The decoded URL or {@code null} if the input was * {@code null}. */ static String decodeUrl(final String url) { String decoded = url; if (url != null && url.indexOf('%') >= 0) { final int n = url.length(); final StringBuilder buffer = new StringBuilder(); final ByteBuffer bytes = ByteBuffer.allocate(n); for (int i = 0; i < n; ) { if (url.charAt(i) == '%') { try { do { final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16); bytes.put(octet); i += 3; } while (i < n && url.charAt(i) == '%'); continue; } catch (final RuntimeException e) { // malformed percent-encoded octet, fall through and // append characters literally } finally { if (bytes.position() > 0) { bytes.flip(); buffer.append(StandardCharsets.UTF_8.decode(bytes).toString()); bytes.clear(); } } } buffer.append(url.charAt(i++)); } decoded = buffer.toString(); } return decoded; } /** * Deletes the given File but throws an IOException if it cannot, unlike {@link File#delete()} which returns a * boolean. * * @param file The file to delete. * @return the given file. * @throws IOException if the file cannot be deleted. * @see File#delete() * @since 2.9.0 */ public static File delete(final File file) throws IOException { Objects.requireNonNull(file, "file"); Files.delete(file.toPath()); return file; } /** * Deletes a directory recursively. * * @param directory directory to delete * @throws IOException in case deletion is unsuccessful * @throws IllegalArgumentException if {@code directory} is not a directory */ public static void deleteDirectory(final File directory) throws IOException { Objects.requireNonNull(directory, "directory"); if (!directory.exists()) { return; } if (!isSymlink(directory)) { cleanDirectory(directory); } delete(directory); } /** * Schedules a directory recursively for deletion on JVM exit. * * @param directory directory to delete, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws IOException in case deletion is unsuccessful */ private static void deleteDirectoryOnExit(final File directory) throws IOException { if (!directory.exists()) { return; } directory.deleteOnExit(); if (!isSymlink(directory)) { cleanDirectoryOnExit(directory); } } /** * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. ** The difference between File.delete() and this method are: *
** Files are normalized before comparison. *
* * Edge cases: ** The difference between File.delete() and this method are: *
*Note: The input date is assumed to be in the system default time-zone with the time * part set to the current time. To use a non-default time-zone use the method * {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) * isFileNewer(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where * {@code zoneId} is a valid {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDate the date reference. * @return true if the {@code File} exists and has been modified after the given * {@code ChronoLocalDate} at the current time. * @throws NullPointerException if the file or local date is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate) { return isFileNewer(file, chronoLocalDate, LocalTime.now()); } /** * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDate} * at the specified time. * *
Note: The input date and time are assumed to be in the system default time-zone. To use a * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) * isFileNewer(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid * {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDate the date reference. * @param localTime the time reference. * @return true if the {@code File} exists and has been modified after the given * {@code ChronoLocalDate} at the given time. * @throws NullPointerException if the file, local date or zone ID is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); Objects.requireNonNull(localTime, "localTime"); return isFileNewer(file, chronoLocalDate.atTime(localTime)); } /** * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDateTime} * at the system-default time zone. * *
Note: The input date and time is assumed to be in the system default time-zone. To use a * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId) * isFileNewer(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid * {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDateTime the date reference. * @return true if the {@code File} exists and has been modified after the given * {@code ChronoLocalDateTime} at the system-default time zone. * @throws NullPointerException if the file or local date time is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final ChronoLocalDateTime> chronoLocalDateTime) { return isFileNewer(file, chronoLocalDateTime, ZoneId.systemDefault()); } /** * Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDateTime} * at the specified {@code ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDateTime the date reference. * @param zoneId the time zone. * @return true if the {@code File} exists and has been modified after the given * {@code ChronoLocalDateTime} at the given {@code ZoneId}. * @throws NullPointerException if the file, local date time or zone ID is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final ChronoLocalDateTime> chronoLocalDateTime, final ZoneId zoneId) { Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); Objects.requireNonNull(zoneId, "zoneId"); return isFileNewer(file, chronoLocalDateTime.atZone(zoneId)); } /** * Tests if the specified {@code File} is newer than the specified {@code ChronoZonedDateTime}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoZonedDateTime the date reference. * @return true if the {@code File} exists and has been modified after the given * {@code ChronoZonedDateTime}. * @throws NullPointerException if the file or zoned date time is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final ChronoZonedDateTime> chronoZonedDateTime) { Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); return isFileNewer(file, chronoZonedDateTime.toInstant()); } /** * Tests if the specified {@code File} is newer than the specified {@code Date}. * * @param file the {@code File} of which the modification date must be compared. * @param date the date reference. * @return true if the {@code File} exists and has been modified * after the given {@code Date}. * @throws NullPointerException if the file or date is {@code null}. */ public static boolean isFileNewer(final File file, final Date date) { Objects.requireNonNull(date, "date"); return isFileNewer(file, date.getTime()); } /** * Tests if the specified {@code File} is newer than the reference {@code File}. * * @param file the {@code File} of which the modification date must be compared. * @param reference the {@code File} of which the modification date is used. * @return true if the {@code File} exists and has been modified more * recently than the reference {@code File}. * @throws NullPointerException if the file or reference file is {@code null}. * @throws IllegalArgumentException if the reference file doesn't exist. */ public static boolean isFileNewer(final File file, final File reference) { requireExists(reference, "reference"); return isFileNewer(file, lastModifiedUnchecked(reference)); } /** * Tests if the specified {@code File} is newer than the specified {@code Instant}. * * @param file the {@code File} of which the modification date must be compared. * @param instant the date reference. * @return true if the {@code File} exists and has been modified after the given {@code Instant}. * @throws NullPointerException if the file or instant is {@code null}. * * @since 2.8.0 */ public static boolean isFileNewer(final File file, final Instant instant) { Objects.requireNonNull(instant, "instant"); return isFileNewer(file, instant.toEpochMilli()); } /** * Tests if the specified {@code File} is newer than the specified time reference. * * @param file the {@code File} of which the modification date must be compared. * @param timeMillis the time reference measured in milliseconds since the * epoch (00:00:00 GMT, January 1, 1970). * @return true if the {@code File} exists and has been modified after the given time reference. * @throws NullPointerException if the file is {@code null}. */ public static boolean isFileNewer(final File file, final long timeMillis) { Objects.requireNonNull(file, "file"); return file.exists() && lastModifiedUnchecked(file) > timeMillis; } /** * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDate} * at the current time. * *
Note: The input date is assumed to be in the system default time-zone with the time * part set to the current time. To use a non-default time-zone use the method * {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) * isFileOlder(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where * {@code zoneId} is a valid {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDate the date reference. * @return true if the {@code File} exists and has been modified before the given * {@code ChronoLocalDate} at the current time. * @throws NullPointerException if the file or local date is {@code null}. * @see ZoneId#systemDefault() * @see LocalTime#now() * * @since 2.8.0 */ public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate) { return isFileOlder(file, chronoLocalDate, LocalTime.now()); } /** * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDate} * at the specified {@code LocalTime}. * *
Note: The input date and time are assumed to be in the system default time-zone. To use a * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) * isFileOlder(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid * {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDate the date reference. * @param localTime the time reference. * @return true if the {@code File} exists and has been modified before the * given {@code ChronoLocalDate} at the specified time. * @throws NullPointerException if the file, local date or local time is {@code null}. * @see ZoneId#systemDefault() * * @since 2.8.0 */ public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) { Objects.requireNonNull(chronoLocalDate, "chronoLocalDate"); Objects.requireNonNull(localTime, "localTime"); return isFileOlder(file, chronoLocalDate.atTime(localTime)); } /** * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDateTime} * at the system-default time zone. * *
Note: The input date and time is assumed to be in the system default time-zone. To use a * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId) * isFileOlder(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid * {@link ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDateTime the date reference. * @return true if the {@code File} exists and has been modified before the given * {@code ChronoLocalDateTime} at the system-default time zone. * @throws NullPointerException if the file or local date time is {@code null}. * @see ZoneId#systemDefault() * * @since 2.8.0 */ public static boolean isFileOlder(final File file, final ChronoLocalDateTime> chronoLocalDateTime) { return isFileOlder(file, chronoLocalDateTime, ZoneId.systemDefault()); } /** * Tests if the specified {@code File} is older than the specified {@code ChronoLocalDateTime} * at the specified {@code ZoneId}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoLocalDateTime the date reference. * @param zoneId the time zone. * @return true if the {@code File} exists and has been modified before the given * {@code ChronoLocalDateTime} at the given {@code ZoneId}. * @throws NullPointerException if the file, local date time or zone ID is {@code null}. * * @since 2.8.0 */ public static boolean isFileOlder(final File file, final ChronoLocalDateTime> chronoLocalDateTime, final ZoneId zoneId) { Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime"); Objects.requireNonNull(zoneId, "zoneId"); return isFileOlder(file, chronoLocalDateTime.atZone(zoneId)); } /** * Tests if the specified {@code File} is older than the specified {@code ChronoZonedDateTime}. * * @param file the {@code File} of which the modification date must be compared. * @param chronoZonedDateTime the date reference. * @return true if the {@code File} exists and has been modified before the given * {@code ChronoZonedDateTime}. * @throws NullPointerException if the file or zoned date time is {@code null}. * * @since 2.8.0 */ public static boolean isFileOlder(final File file, final ChronoZonedDateTime> chronoZonedDateTime) { Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime"); return isFileOlder(file, chronoZonedDateTime.toInstant()); } /** * Tests if the specified {@code File} is older than the specified {@code Date}. * * @param file the {@code File} of which the modification date must be compared. * @param date the date reference. * @return true if the {@code File} exists and has been modified before the given {@code Date}. * @throws NullPointerException if the file or date is {@code null}. */ public static boolean isFileOlder(final File file, final Date date) { Objects.requireNonNull(date, "date"); return isFileOlder(file, date.getTime()); } /** * Tests if the specified {@code File} is older than the reference {@code File}. * * @param file the {@code File} of which the modification date must be compared. * @param reference the {@code File} of which the modification date is used. * @return true if the {@code File} exists and has been modified before the reference {@code File}. * @throws NullPointerException if the file or reference file is {@code null}. * @throws IllegalArgumentException if the reference file doesn't exist. */ public static boolean isFileOlder(final File file, final File reference) { requireExists(reference, "reference"); return isFileOlder(file, lastModifiedUnchecked(reference)); } /** * Tests if the specified {@code File} is older than the specified {@code Instant}. * * @param file the {@code File} of which the modification date must be compared. * @param instant the date reference. * @return true if the {@code File} exists and has been modified before the given {@code Instant}. * @throws NullPointerException if the file or instant is {@code null}. * @since 2.8.0 */ public static boolean isFileOlder(final File file, final Instant instant) { Objects.requireNonNull(instant, "instant"); return isFileOlder(file, instant.toEpochMilli()); } /** * Tests if the specified {@code File} is older than the specified time reference. * * @param file the {@code File} of which the modification date must be compared. * @param timeMillis the time reference measured in milliseconds since the * epoch (00:00:00 GMT, January 1, 1970). * @return true if the {@code File} exists and has been modified before the given time reference. * @throws NullPointerException if the file is {@code null}. */ public static boolean isFileOlder(final File file, final long timeMillis) { Objects.requireNonNull(file, "file"); return file.exists() && lastModifiedUnchecked(file) < timeMillis; } /** * Tests whether the specified {@code File} is a regular file or not. Implemented as a * null-safe delegate to {@code Files.isRegularFile(Path path, LinkOption... options)}. * * @param file the path to the file. * @param options options indicating how symbolic links are handled * @return {@code true} if the file is a regular file; {@code false} if * the path is null, the file does not exist, is not a directory, or it cannot * be determined if the file is a regular file or not. * @throws SecurityException In the case of the default provider, and a security manager is installed, the * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read * access to the directory. * @since 2.9.0 */ public static boolean isRegularFile(final File file, final LinkOption... options) { return file != null && Files.isRegularFile(file.toPath(), options); } /** * Tests whether the specified file is a symbolic link rather than an actual file. *
* This method delegates to {@link Files#isSymbolicLink(Path path)} *
* * @param file the file to test. * @return true if the file is a symbolic link, see {@link Files#isSymbolicLink(Path path)}. * @since 2.0 * @see Files#isSymbolicLink(Path) */ public static boolean isSymlink(final File file) { return file != null && Files.isSymbolicLink(file.toPath()); } /** * Iterates over the files in given directory (and optionally * its subdirectories). ** The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. *
** All files found are filtered by an IOFileFilter. *
* * @param directory the directory to search in * @param fileFilter filter to apply when finding files. * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use TrueFileFilter.INSTANCE to match all directories. * @return an iterator of java.io.File for the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 1.2 */ public static Iterator* The resulting iterator MUST be consumed in its entirety in order to close its underlying stream. *
*
*
* @param directory the directory to search in
* @param extensions an array of extensions, ex. {"java","xml"}. If this
* parameter is {@code null}, all files are returned.
* @param recursive if true all subdirectories are searched as well
* @return an iterator of java.io.File with the matching files
* @since 1.2
*/
public static Iterator
* The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
*
* All files found are filtered by an IOFileFilter.
*
* The resulting iterator includes the subdirectories themselves.
*
* Use this method to avoid issues with {@link File#lastModified()} like
* JDK-8177809 where {@link File#lastModified()} is
* losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
*
* Use this method to avoid issues with {@link File#lastModified()} like
* JDK-8177809 where {@link File#lastModified()} is
* losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
*
* This method opens an {@code InputStream} for the file.
* When you have finished with the iterator you should close the stream
* to free internal resources. This can be done by calling the
* {@link LineIterator#close()} or
* {@link LineIterator#closeQuietly(LineIterator)} method.
*
* The recommended usage pattern is:
*
* If an exception occurs during the creation of the iterator, the
* underlying stream is closed.
*
* If your search should recurse into subdirectories you can pass in
* an IOFileFilter for directories. You don't need to bind a
* DirectoryFileFilter (via logical AND) to this filter. This method does
* that for you.
*
* An example: If you want to search through all directories called
* "temp" you pass in {@code FileFilterUtils.NameFileFilter("temp")}
*
* Another common usage of this method is find files in a directory
* tree but ignoring the directories generated CVS. You can simply pass
* in {@code FileFilterUtils.makeCVSAware(null)}.
*
* The resulting collection includes the starting directory and
* any subdirectories that match the directory filter.
*
* When the destination directory is on another file system, do a "copy and delete".
*
* Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}.
*
* When the destination file is on another file system, do a "copy and delete".
*
* When the destination file is on another file system, do a "copy and delete".
*
* When the destination is on another file system, do a "copy and delete".
*
* At the end of the method either the stream will be successfully opened, or an exception will have been thrown.
*
* An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a
* directory. An exception is thrown if the file exists but cannot be read.
*
* At the end of the method either the stream will be successfully opened,
* or an exception will have been thrown.
*
* The parent directory will be created if it does not exist.
* The file will be created if it does not exist.
* An exception is thrown if the file object exists but is a directory.
* An exception is thrown if the file exists but cannot be written to.
* An exception is thrown if the parent directory cannot be created.
*
* At the end of the method either the stream will be successfully opened,
* or an exception will have been thrown.
*
* The parent directory will be created if it does not exist.
* The file will be created if it does not exist.
* An exception is thrown if the file object exists but is a directory.
* An exception is thrown if the file exists but cannot be written to.
* An exception is thrown if the parent directory cannot be created.
*
* Note that overflow is not detected, and the return value may be negative if
* overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative
* method that does not overflow.
*
* Note that overflow is not detected, and the return value may be negative if
* overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative
* method that does not overflow.
*
* From version 1.1 this method will decode the URL.
* Syntax such as {@code file:///my%20docs/file.txt} will be
* correctly decoded to {@code /my docs/file.txt}. Starting with version
* 1.5, this method uses UTF-8 to decode percent-encoded octets to characters.
* Additionally, malformed percent-encoded octets are handled leniently by
* passing them through literally.
*
* Returns an array of the same size as the input.
* If the input is {@code null}, an empty array is returned.
* If the input contains {@code null}, the output array contains {@code null} at the same
* index.
*
* This method will decode the URL.
* Syntax such as {@code file:///my%20docs/file.txt} will be
* correctly decoded to {@code /my docs/file.txt}.
*
* NOTE: As from v1.3, this method throws an IOException if the last
* modified date of the file cannot be set. Also, as from v1.3 this method
* creates parent directories if they do not exist.
*
* Returns an array of the same size as the input.
*
* This method repeatedly tests {@link File#exists()} until it returns
* true up to the maximum time specified in seconds.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* NOTE: As from v1.3, the parent directories of the file will be created
* if they do not exist.
*
* LineIterator it = FileUtils.lineIterator(file, "UTF-8");
* try {
* while (it.hasNext()) {
* String line = it.nextLine();
* /// do something with line
* }
* } finally {
* LineIterator.closeQuietly(iterator);
* }
*
*
*
*
* @param source the file or directory to be moved
* @param destination the destination file or directory
* @throws FileNotFoundException if {@code source} file does not exist
*/
private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException {
Objects.requireNonNull(source, "source");
Objects.requireNonNull(destination, "destination");
if (!source.exists()) {
throw new FileNotFoundException("Source '" + source + "' does not exist");
}
}
/**
* Waits for NFS to propagate a file creation, imposing a timeout.
*