Categories:
Audio (13)
Biotech (29)
Bytecode (36)
Database (77)
Framework (7)
Game (7)
General (507)
Graphics (53)
I/O (35)
IDE (2)
JAR Tools (101)
JavaBeans (21)
JDBC (121)
JDK (426)
JSP (20)
Logging (108)
Mail (58)
Messaging (8)
Network (84)
PDF (97)
Report (7)
Scripting (84)
Security (32)
Server (121)
Servlet (26)
SOAP (24)
Testing (54)
Web (15)
XML (309)
Collections:
Other Resources:
commons-io-2.6-sources.jar - Apache Commons IO
commons-io-2.6-sources.jar is the source JAR file for Apache Commons IO 2.6, which is a library of utilities to assist with developing IO functionality.
JAR File Size and Download Location:
JAR name: commons-io-2.6-sources.jar Target JDK version: 1.7 Dependency: None File size: 280,834 bytes Release date: 15-Oct-2017 Download: Apache Commons IO Website
✍: FYIcenter.com
⏎ org/apache/commons/io/FileUtils.java
/* * 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.math.BigInteger; import java.net.URL; import java.net.URLConnection; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.zip.CRC32; import java.util.zip.CheckedInputStream; import java.util.zip.Checksum; import org.apache.commons.io.filefilter.DirectoryFileFilter; import org.apache.commons.io.filefilter.FalseFileFilter; import org.apache.commons.io.filefilter.FileFilterUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.SuffixFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.io.output.NullOutputStream; /** * General file manipulation utilities. * <p> * Facilities are provided in the following areas: * <ul> * <li>writing to a file * <li>reading from a file * <li>make a directory including parent directories * <li>copying files and directories * <li>deleting files and directories * <li>converting to and from a URL * <li>listing files and directories by filter and extension * <li>comparing file content * <li>file last changed date * <li>calculating a checksum * </ul> * <p> * 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. * <p> * Origin of code: Excalibur, Alexandria, Commons-Utils * */ public class FileUtils { /** * Instances should NOT be constructed in standard programming. */ public FileUtils() { super(); } /** * 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 file copy buffer size (30 MB) */ private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30; /** * 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</code>. */ public static final File[] EMPTY_FILE_ARRAY = new File[0]; //----------------------------------------------------------------------- /** * Construct a file from the set of name elements. * * @param directory the parent directory * @param names the name elements * @return the file * @since 2.1 */ public static File getFile(final File directory, final String... names) { if (directory == null) { throw new NullPointerException("directory must not be null"); } if (names == null) { throw new NullPointerException("names must not be null"); } File file = directory; for (final String name : names) { file = new File(file, name); } return file; } /** * Construct a file from the set of name elements. * * @param names the name elements * @return the file * @since 2.1 */ public static File getFile(final String... names) { if (names == null) { throw new NullPointerException("names must not be null"); } File file = null; for (final String name : names) { if (file == null) { file = new File(name); } else { file = new File(file, name); } } return file; } /** * Returns the path to the system temporary directory. * * @return the path to the system temporary directory. * * @since 2.0 */ public static String getTempDirectoryPath() { return System.getProperty("java.io.tmpdir"); } /** * Returns a {@link File} representing the system temporary directory. * * @return the system temporary directory. * * @since 2.0 */ public static File getTempDirectory() { return new File(getTempDirectoryPath()); } /** * Returns the path to the user's home directory. * * @return the path to the user's home directory. * * @since 2.0 */ public static String getUserDirectoryPath() { return System.getProperty("user.home"); } /** * Returns a {@link File} representing the user's home directory. * * @return the user's home directory. * * @since 2.0 */ public static File getUserDirectory() { return new File(getUserDirectoryPath()); } //----------------------------------------------------------------------- /** * Opens a {@link FileInputStream} for the specified file, providing better * error messages than simply calling <code>new FileInputStream(file)</code>. * <p> * At the end of the method either the stream will be successfully opened, * or an exception will have been thrown. * <p> * 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. * * @param file the file to open for input, must not be {@code null} * @return a new {@link FileInputStream} for the specified file * @throws FileNotFoundException if the file does not exist * @throws IOException if the file object is a directory * @throws IOException if the file cannot be read * @since 1.3 */ public static FileInputStream openInputStream(final File file) throws IOException { if (file.exists()) { if (file.isDirectory()) { throw new IOException("File '" + file + "' exists but is a directory"); } if (file.canRead() == false) { throw new IOException("File '" + file + "' cannot be read"); } } else { throw new FileNotFoundException("File '" + file + "' does not exist"); } return new FileInputStream(file); } //----------------------------------------------------------------------- /** * Opens a {@link FileOutputStream} for the specified file, checking and * creating the parent directory if it does not exist. * <p> * At the end of the method either the stream will be successfully opened, * or an exception will have been thrown. * <p> * 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. * * @param file the file to open for output, must not be {@code null} * @return a new {@link FileOutputStream} for the specified file * @throws IOException if the file object is a directory * @throws IOException if the file cannot be written to * @throws IOException if a parent directory needs creating but that fails * @since 1.3 */ public static FileOutputStream openOutputStream(final File file) throws IOException { return openOutputStream(file, false); } /** * Opens a {@link FileOutputStream} for the specified file, checking and * creating the parent directory if it does not exist. * <p> * At the end of the method either the stream will be successfully opened, * or an exception will have been thrown. * <p> * 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. * * @param file the file to open for output, must not be {@code null} * @param append if {@code true}, then bytes will be added to the * end of the file rather than overwriting * @return a new {@link FileOutputStream} for the specified file * @throws IOException if the file object is a directory * @throws IOException if the file cannot be written to * @throws IOException if a parent directory needs creating but that fails * @since 2.1 */ public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException { if (file.exists()) { if (file.isDirectory()) { throw new IOException("File '" + file + "' exists but is a directory"); } if (file.canWrite() == false) { throw new IOException("File '" + file + "' cannot be written to"); } } else { final File parent = file.getParentFile(); if (parent != null) { if (!parent.mkdirs() && !parent.isDirectory()) { throw new IOException("Directory '" + parent + "' could not be created"); } } } return new FileOutputStream(file, append); } //----------------------------------------------------------------------- /** * Returns a human-readable version of the file size, where the input represents a specific number of bytes. * <p> * 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. * </p> * <p> * Similarly for the 1MB and 1KB boundaries. * </p> * * @param size the number of bytes * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> * @since 2.4 */ // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed? public static String byteCountToDisplaySize(final BigInteger size) { String displaySize; if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_EB_BI)) + " EB"; } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_PB_BI)) + " PB"; } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_TB_BI)) + " TB"; } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_GB_BI)) + " GB"; } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_MB_BI)) + " MB"; } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) { displaySize = String.valueOf(size.divide(ONE_KB_BI)) + " KB"; } else { displaySize = String.valueOf(size) + " bytes"; } return displaySize; } /** * Returns a human-readable version of the file size, where the input represents a specific number of bytes. * <p> * 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. * </p> * <p> * Similarly for the 1MB and 1KB boundaries. * </p> * * @param size the number of bytes * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes) * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a> */ // 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)); } //----------------------------------------------------------------------- /** * Implements the same behaviour as the "touch" utility on Unix. It creates * a new file with size 0 or, if the file exists already, it is opened and * closed without modifying it, but updating the file date and time. * <p> * 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. * * @param file the File to touch * @throws IOException If an I/O problem occurs */ public static void touch(final File file) throws IOException { if (!file.exists()) { openOutputStream(file).close(); } final boolean success = file.setLastModified(System.currentTimeMillis()); if (!success) { throw new IOException("Unable to set the last modification time for " + file); } } //----------------------------------------------------------------------- /** * 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<File> files) { return files.toArray(new File[files.size()]); } //----------------------------------------------------------------------- /** * Finds files within a given directory (and optionally its * subdirectories). All files found are filtered by an IOFileFilter. * * @param files the collection of files found. * @param directory the directory to search in. * @param filter the filter to apply to files and directories. * @param includeSubDirectories indicates if will include the subdirectories themselves */ private static void innerListFiles(final Collection<File> files, final File directory, final IOFileFilter filter, final boolean includeSubDirectories) { final File[] found = directory.listFiles((FileFilter) filter); if (found != null) { for (final File file : found) { if (file.isDirectory()) { if (includeSubDirectories) { files.add(file); } innerListFiles(files, file, filter, includeSubDirectories); } else { files.add(file); } } } } /** * Finds files within a given directory (and optionally its * subdirectories). All files found are filtered by an IOFileFilter. * <p> * 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. * <p> * An example: If you want to search through all directories called * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code> * <p> * 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)</code>. * * @param directory the directory to search in * @param fileFilter filter to apply when finding files. Must not be {@code null}, * use {@link TrueFileFilter#INSTANCE} to match all files in selected directories. * @param dirFilter optional filter to apply when finding subdirectories. * If this parameter is {@code null}, subdirectories will not be included in the * search. Use {@link TrueFileFilter#INSTANCE} to match all directories. * @return a collection of java.io.File with the matching files * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter */ public static Collection<File> listFiles( final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { validateListFilesParameters(directory, fileFilter); final IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter); final IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter); //Find files final Collection<File> files = new java.util.LinkedList<>(); innerListFiles(files, directory, FileFilterUtils.or(effFileFilter, effDirFilter), false); return files; } /** * Validates the given arguments. * <ul> * <li>Throws {@link IllegalArgumentException} if {@code directory} is not a directory</li> * <li>Throws {@link NullPointerException} if {@code fileFilter} is null</li> * </ul> * * @param directory The File to test * @param fileFilter The IOFileFilter to test */ private static void validateListFilesParameters(final File directory, final IOFileFilter fileFilter) { if (!directory.isDirectory()) { throw new IllegalArgumentException("Parameter 'directory' is not a directory: " + directory); } if (fileFilter == null) { throw new NullPointerException("Parameter 'fileFilter' is null"); } } /** * Returns a filter that accepts files in addition to the {@link File} objects accepted by the given filter. * * @param fileFilter a base filter to add to * @return a filter that accepts files */ private static IOFileFilter setUpEffectiveFileFilter(final IOFileFilter fileFilter) { return FileFilterUtils.and(fileFilter, FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE)); } /** * Returns a filter that accepts directories in addition to the {@link File} objects accepted by the given filter. * * @param dirFilter a base filter to add to * @return a filter that accepts directories */ private static IOFileFilter setUpEffectiveDirFilter(final IOFileFilter dirFilter) { return dirFilter == null ? FalseFileFilter.INSTANCE : FileFilterUtils.and(dirFilter, DirectoryFileFilter.INSTANCE); } /** * Finds files within a given directory (and optionally its * subdirectories). All files found are filtered by an IOFileFilter. * <p> * The resulting collection includes the starting directory and * any subdirectories that match the directory filter. * <p> * * @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 a collection of java.io.File with the matching files * @see org.apache.commons.io.FileUtils#listFiles * @see org.apache.commons.io.filefilter.FileFilterUtils * @see org.apache.commons.io.filefilter.NameFileFilter * @since 2.2 */ public static Collection<File> listFilesAndDirs( final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { validateListFilesParameters(directory, fileFilter); final IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter); final IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter); //Find files final Collection<File> files = new java.util.LinkedList<>(); if (directory.isDirectory()) { files.add(directory); } innerListFiles(files, directory, FileFilterUtils.or(effFileFilter, effDirFilter), true); return files; } /** * Allows iteration over the files in given directory (and optionally * its subdirectories). * <p> * All files found are filtered by an IOFileFilter. This method is * based on {@link #listFiles(File, IOFileFilter, IOFileFilter)}, * which supports Iterable ('foreach' loop). * <p> * @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<File> iterateFiles( final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { return listFiles(directory, fileFilter, dirFilter).iterator(); } /** * Allows iteration over the files in given directory (and optionally * its subdirectories). * <p> * All files found are filtered by an IOFileFilter. This method is * based on {@link #listFilesAndDirs(File, IOFileFilter, IOFileFilter)}, * which supports Iterable ('foreach' loop). * <p> * The resulting iterator includes the subdirectories themselves. * * @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 2.2 */ public static Iterator<File> iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) { return listFilesAndDirs(directory, fileFilter, dirFilter).iterator(); } //----------------------------------------------------------------------- /** * Converts an array of file extensions to suffixes for use * with IOFileFilters. * * @param extensions an array of extensions. Format: {"java", "xml"} * @return an array of suffixes. Format: {".java", ".xml"} */ private static String[] toSuffixes(final String[] extensions) { final String[] suffixes = new String[extensions.length]; for (int i = 0; i < extensions.length; i++) { suffixes[i] = "." + extensions[i]; } return suffixes; } /** * Finds files within a given directory (and optionally its subdirectories) * which match an array of extensions. * * @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 a collection of java.io.File with the matching files */ public static Collection<File> listFiles( final File directory, final String[] extensions, final boolean recursive) { IOFileFilter filter; if (extensions == null) { filter = TrueFileFilter.INSTANCE; } else { final String[] suffixes = toSuffixes(extensions); filter = new SuffixFileFilter(suffixes); } return listFiles(directory, filter, recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE); } /** * Allows iteration over the files in a given directory (and optionally * its subdirectories) which match an array of extensions. This method * is based on {@link #listFiles(File, String[], boolean)}, * which supports Iterable ('foreach' loop). * * @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<File> iterateFiles( final File directory, final String[] extensions, final boolean recursive) { return listFiles(directory, extensions, recursive).iterator(); } //----------------------------------------------------------------------- /** * Compares the contents of two files to determine if they are equal or not. * <p> * 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. * <p> * 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 IOException in case of an I/O error */ public static boolean contentEquals(final File file1, final File file2) throws IOException { final boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } if (file1.isDirectory() || file2.isDirectory()) { // don't want to compare directory contents throw new IOException("Can't compare directories, only files"); } 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 = new FileInputStream(file1); InputStream input2 = new FileInputStream(file2)) { return IOUtils.contentEquals(input1, input2); } } //----------------------------------------------------------------------- /** * Compares the contents of two files to determine if they are equal or not. * <p> * This method checks to see if the two files point to the same file, * before resorting to line-by-line comparison of the contents. * <p> * * @param file1 the first file * @param file2 the second file * @param charsetName the character encoding to be used. * 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 IOException in case of an I/O error * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader) * @since 2.2 */ public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName) throws IOException { final boolean file1Exists = file1.exists(); if (file1Exists != file2.exists()) { return false; } if (!file1Exists) { // two not existing files are equal return true; } if (file1.isDirectory() || file2.isDirectory()) { // don't want to compare directory contents throw new IOException("Can't compare directories, only files"); } if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) { // same file return true; } try (Reader input1 = charsetName == null ? new InputStreamReader(new FileInputStream(file1), Charset.defaultCharset()) : new InputStreamReader(new FileInputStream(file1), charsetName); Reader input2 = charsetName == null ? new InputStreamReader(new FileInputStream(file2), Charset.defaultCharset()) : new InputStreamReader(new FileInputStream(file2), charsetName)) { return IOUtils.contentEqualsIgnoreEOL(input1, input2); } } //----------------------------------------------------------------------- /** * Convert from a <code>URL</code> to a <code>File</code>. * <p> * From version 1.1 this method will decode the URL. * Syntax such as <code>file:///my%20docs/file.txt</code> will be * correctly decoded to <code>/my docs/file.txt</code>. 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. * * @param url the file URL to convert, {@code null} returns {@code null} * @return the equivalent <code>File</code> object, or {@code null} * if the URL's protocol is not <code>file</code> */ public static File toFile(final URL url) { if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) { return null; } else { String filename = url.getFile().replace('/', File.separatorChar); filename = decodeUrl(filename); return new File(filename); } } /** * 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; } /** * Converts each of an array of <code>URL</code> to a <code>File</code>. * <p> * 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. * <p> * This method will decode the URL. * Syntax such as <code>file:///my%20docs/file.txt</code> will be * correctly decoded to <code>/my docs/file.txt</code>. * * @param urls the file URLs to convert, {@code null} returns empty array * @return a non-{@code null} array of Files matching the input, with a {@code null} item * if there was a {@code null} at that index in the input array * @throws IllegalArgumentException if any file is not a URL file * @throws IllegalArgumentException if any file is incorrectly encoded * @since 1.1 */ public static File[] toFiles(final URL[] urls) { if (urls == null || urls.length == 0) { return EMPTY_FILE_ARRAY; } final File[] files = new File[urls.length]; for (int i = 0; i < urls.length; i++) { final URL url = urls[i]; if (url != null) { if (url.getProtocol().equals("file") == false) { throw new IllegalArgumentException( "URL could not be converted to a File: " + url); } files[i] = toFile(url); } } return files; } /** * Converts each of an array of <code>File</code> to a <code>URL</code>. * <p> * Returns an array of the same size as the input. * * @param files the files to convert, must not be {@code null} * @return an array of URLs matching the input * @throws IOException if a file cannot be converted * @throws NullPointerException if the parameter is null */ public static URL[] toURLs(final File[] files) throws IOException { final URL[] urls = new URL[files.length]; for (int i = 0; i < urls.length; i++) { urls[i] = files[i].toURI().toURL(); } return urls; } //----------------------------------------------------------------------- /** * Copies a file to a directory preserving the file date. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @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 source or destination is null * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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. * <p> * 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. * <p> * <strong>Note:</strong> Setting <code>preserveFileDate</code> 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, no indication is provided. * * @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} * @param preserveFileDate true if the file date of the copy * should be the same as the original * * @throws NullPointerException if source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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) * @since 1.3 */ public static void copyFileToDirectory(final File srcFile, final File destDir, final boolean preserveFileDate) throws IOException { if (destDir == null) { throw new NullPointerException("Destination must not be null"); } if (destDir.exists() && destDir.isDirectory() == false) { throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory"); } final File destFile = new File(destDir, srcFile.getName()); copyFile(srcFile, destFile, preserveFileDate); } /** * Copies a file to a new location preserving the file date. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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, true); } /** * Copies a file to a new location. * <p> * 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. * <p> * <strong>Note:</strong> Setting <code>preserveFileDate</code> 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, no indication is provided. * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @throws IOException if the output file length is not the same as the input file length after the copy * completes * @see #copyFileToDirectory(File, File, boolean) * @see #doCopyFile(File, File, boolean) */ public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException { checkFileRequirements(srcFile, destFile); if (srcFile.isDirectory()) { throw new IOException("Source '" + srcFile + "' exists but is a directory"); } if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) { throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same"); } final File parentFile = destFile.getParentFile(); if (parentFile != null) { if (!parentFile.mkdirs() && !parentFile.isDirectory()) { throw new IOException("Destination '" + parentFile + "' directory cannot be created"); } } if (destFile.exists() && destFile.canWrite() == false) { throw new IOException("Destination '" + destFile + "' exists but is read-only"); } doCopyFile(srcFile, destFile, preserveFileDate); } /** * Copy bytes from a <code>File</code> to an <code>OutputStream</code>. * <p> * This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>. * </p> * * @param input the <code>File</code> to read from * @param output the <code>OutputStream</code> to write to * @return the number of bytes copied * @throws NullPointerException if the input or output is 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 (FileInputStream fis = new FileInputStream(input)) { return IOUtils.copyLarge(fis, output); } } /** * Internal copy file method. * This caches the original file length, and throws an IOException * if the output file length is different from the current input file length. * So it may fail if the file changes size. * It may also fail with "IllegalArgumentException: Negative size" if the input file is truncated part way * through copying the data and the new file size is less than the current position. * * @param srcFile the validated source file, must not be {@code null} * @param destFile the validated destination file, must not be {@code null} * @param preserveFileDate whether to preserve the file date * @throws IOException if an error occurs * @throws IOException if the output file length is not the same as the input file length after the * copy completes * @throws IllegalArgumentException "Negative size" if the file is truncated so that the size is less than the * position */ private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException { if (destFile.exists() && destFile.isDirectory()) { throw new IOException("Destination '" + destFile + "' exists but is a directory"); } try (FileInputStream fis = new FileInputStream(srcFile); FileChannel input = fis.getChannel(); FileOutputStream fos = new FileOutputStream(destFile); FileChannel output = fos.getChannel()) { final long size = input.size(); // TODO See IO-386 long pos = 0; long count = 0; while (pos < size) { final long remain = size - pos; count = remain > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : remain; final long bytesCopied = output.transferFrom(input, pos, count); if (bytesCopied == 0) { // IO-385 - can happen if file is truncated after caching the size break; // ensure we don't loop forever } pos += bytesCopied; } } final long srcLen = srcFile.length(); // TODO See IO-386 final long dstLen = destFile.length(); // TODO See IO-386 if (srcLen != dstLen) { throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile + "' Expected length: " + srcLen + " Actual: " + dstLen); } if (preserveFileDate) { destFile.setLastModified(srcFile.lastModified()); } } //----------------------------------------------------------------------- /** * Copies a directory to within another directory preserving the file dates. * <p> * This method copies the source directory and all its contents to a * directory of the same name in the specified destination directory. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @param srcDir an existing directory to copy, must not be {@code null} * @param destDir the directory to place the copy in, must not be {@code null} * * @throws NullPointerException if source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @since 1.2 */ public static void copyDirectoryToDirectory(final File srcDir, final File destDir) throws IOException { if (srcDir == null) { throw new NullPointerException("Source must not be null"); } if (srcDir.exists() && srcDir.isDirectory() == false) { throw new IllegalArgumentException("Source '" + destDir + "' is not a directory"); } if (destDir == null) { throw new NullPointerException("Destination must not be null"); } if (destDir.exists() && destDir.isDirectory() == false) { throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory"); } copyDirectory(srcDir, new File(destDir, srcDir.getName()), true); } /** * Copies a whole directory to a new location preserving the file dates. * <p> * 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. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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. * <p> * This method copies the contents of the specified source directory * to within the specified destination directory. * <p> * 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. * <p> * <strong>Note:</strong> Setting <code>preserveFileDate</code> 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, no indication is provided. * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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. * <p> * This method copies the contents of the specified source directory * to within the specified destination directory. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * </p> * <h3>Example: Copy directories only</h3> * <pre> * // only copy the directory structure * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY); * </pre> * * <h3>Example: Copy directories and txt files</h3> * <pre> * // 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); * </pre> * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @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. * <p> * This method copies the contents of the specified source directory * to within the specified destination directory. * <p> * 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. * <p> * <strong>Note:</strong> Setting <code>preserveFileDate</code> 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, no indication is provided. * </p> * <h3>Example: Copy directories only</h3> * <pre> * // only copy the directory structure * FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false); * </pre> * * <h3>Example: Copy directories and txt files</h3> * <pre> * // 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); * </pre> * * @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 source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @since 1.4 */ public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate) throws IOException { checkFileRequirements(srcDir, destDir); if (!srcDir.isDirectory()) { throw new IOException("Source '" + srcDir + "' exists but is not a directory"); } if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) { throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same"); } // Cater for destination being directory within the source directory (see IO-141) List<String> exclusionList = null; if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) { final File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter); if (srcFiles != null && srcFiles.length > 0) { exclusionList = new ArrayList<>(srcFiles.length); for (final File srcFile : srcFiles) { final File copiedFile = new File(destDir, srcFile.getName()); exclusionList.add(copiedFile.getCanonicalPath()); } } } doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList); } /** * checks requirements for file copy * @param src the source file * @param dest the destination * @throws FileNotFoundException if the destination does not exist */ private static void checkFileRequirements(final File src, final File dest) throws FileNotFoundException { if (src == null) { throw new NullPointerException("Source must not be null"); } if (dest == null) { throw new NullPointerException("Destination must not be null"); } if (!src.exists()) { throw new FileNotFoundException("Source '" + src + "' does not exist"); } } /** * Internal copy directory method. * * @param srcDir the validated source directory, must not be {@code null} * @param destDir the validated destination directory, must not be {@code null} * @param filter the filter to apply, null means copy all directories and files * @param preserveFileDate whether to preserve the file date * @param exclusionList List of files and directories to exclude from the copy, may be null * @throws IOException if an error occurs * @since 1.1 */ private static void doCopyDirectory(final File srcDir, final File destDir, final FileFilter filter, final boolean preserveFileDate, final List<String> exclusionList) throws IOException { // recurse final File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter); if (srcFiles == null) { // null if abstract pathname does not denote a directory, or if an I/O error occurs throw new IOException("Failed to list contents of " + srcDir); } if (destDir.exists()) { if (destDir.isDirectory() == false) { throw new IOException("Destination '" + destDir + "' exists but is not a directory"); } } else { if (!destDir.mkdirs() && !destDir.isDirectory()) { throw new IOException("Destination '" + destDir + "' directory cannot be created"); } } if (destDir.canWrite() == false) { throw new IOException("Destination '" + destDir + "' cannot be written to"); } for (final File srcFile : srcFiles) { final File dstFile = new File(destDir, srcFile.getName()); if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) { if (srcFile.isDirectory()) { doCopyDirectory(srcFile, dstFile, filter, preserveFileDate, exclusionList); } else { doCopyFile(srcFile, dstFile, preserveFileDate); } } } // Do this last, as the above has probably affected directory metadata if (preserveFileDate) { destDir.setLastModified(srcDir.lastModified()); } } //----------------------------------------------------------------------- /** * Copies bytes from the URL <code>source</code> to a file * <code>destination</code>. The directories up to <code>destination</code> * will be created if they don't already exist. <code>destination</code> * will be overwritten if it already exists. * <p> * 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</code> to copy bytes from, must not be {@code null} * @param destination the non-directory <code>File</code> to write bytes to * (possibly overwriting), must not be {@code null} * @throws IOException if <code>source</code> URL cannot be opened * @throws IOException if <code>destination</code> is a directory * @throws IOException if <code>destination</code> cannot be written * @throws IOException if <code>destination</code> 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 { copyInputStreamToFile(source.openStream(), destination); } /** * Copies bytes from the URL <code>source</code> to a file * <code>destination</code>. The directories up to <code>destination</code> * will be created if they don't already exist. <code>destination</code> * will be overwritten if it already exists. * * @param source the <code>URL</code> to copy bytes from, must not be {@code null} * @param destination the non-directory <code>File</code> to write bytes to * (possibly overwriting), must not be {@code null} * @param connectionTimeout the number of milliseconds until this method * will timeout if no connection could be established to the <code>source</code> * @param readTimeout the number of milliseconds until this method will * timeout if no data could be read from the <code>source</code> * @throws IOException if <code>source</code> URL cannot be opened * @throws IOException if <code>destination</code> is a directory * @throws IOException if <code>destination</code> cannot be written * @throws IOException if <code>destination</code> 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 connectionTimeout, final int readTimeout) throws IOException { final URLConnection connection = source.openConnection(); connection.setConnectTimeout(connectionTimeout); connection.setReadTimeout(readTimeout); copyInputStreamToFile(connection.getInputStream(), destination); } /** * Copies bytes from an {@link InputStream} <code>source</code> to a file * <code>destination</code>. The directories up to <code>destination</code> * will be created if they don't already exist. <code>destination</code> * 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</code> to copy bytes from, must not be {@code null}, will be closed * @param destination the non-directory <code>File</code> to write bytes to * (possibly overwriting), must not be {@code null} * @throws IOException if <code>destination</code> is a directory * @throws IOException if <code>destination</code> cannot be written * @throws IOException if <code>destination</code> 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 in = source) { copyToFile(in, destination); } } /** * Copies bytes from an {@link InputStream} <code>source</code> to a file * <code>destination</code>. The directories up to <code>destination</code> * will be created if they don't already exist. <code>destination</code> * will be overwritten if it already exists. * The {@code source} stream is left open, e.g. for use with {@link java.util.zip.ZipInputStream ZipInputStream}. * See {@link #copyInputStreamToFile(InputStream, File)} for a method that closes the input stream. * * @param source the <code>InputStream</code> to copy bytes from, must not be {@code null} * @param destination the non-directory <code>File</code> to write bytes to * (possibly overwriting), must not be {@code null} * @throws IOException if <code>destination</code> is a directory * @throws IOException if <code>destination</code> cannot be written * @throws IOException if <code>destination</code> needs creating but can't be * @throws IOException if an IO error occurs during copying * @since 2.5 */ public static void copyToFile(final InputStream source, final File destination) throws IOException { try (InputStream in = source; OutputStream out = openOutputStream(destination)) { IOUtils.copy(in, out); } } /** * Copies a file or directory to within another directory preserving the file dates. * <p> * This method copies the source file or directory, along all its contents, to a * directory of the same name in the specified destination directory. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @param src an existing file or directory to copy, must not be {@code null} * @param destDir the directory to place the copy in, must not be {@code null} * * @throws NullPointerException if source or destination is {@code null} * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @see #copyDirectoryToDirectory(File, File) * @see #copyFileToDirectory(File, File) * @since 2.6 */ public static void copyToDirectory(final File src, final File destDir) throws IOException { if (src == null) { throw new NullPointerException("Source must not be null"); } if (src.isFile()) { copyFileToDirectory(src, destDir); } else if (src.isDirectory()) { copyDirectoryToDirectory(src, destDir); } else { throw new IOException("The source " + src + " does not exist"); } } /** * Copies a files to a directory preserving each file's date. * <p> * 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. * <p> * <strong>Note:</strong> 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, no indication is provided. * * @param srcs a existing files to copy, must not be {@code null} * @param destDir the directory to place the copy in, must not be {@code null} * * @throws NullPointerException if source or destination is null * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs during copying * @see #copyFileToDirectory(File, File) * @since 2.6 */ public static void copyToDirectory(final Iterable<File> srcs, final File destDir) throws IOException { if (srcs == null) { throw new NullPointerException("Sources must not be null"); } for (final File src : srcs) { copyFileToDirectory(src, destDir); } } //----------------------------------------------------------------------- /** * Deletes a directory recursively. * * @param directory directory to delete * @throws IOException in case deletion is unsuccessful * @throws IllegalArgumentException if {@code directory} does not exist or is not a directory */ public static void deleteDirectory(final File directory) throws IOException { if (!directory.exists()) { return; } if (!isSymlink(directory)) { cleanDirectory(directory); } if (!directory.delete()) { final String message = "Unable to delete directory " + directory + "."; throw new IOException(message); } } /** * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories. * <p> * The difference between File.delete() and this method are: * <ul> * <li>A directory to be deleted does not have to be empty.</li> * <li>No exceptions are thrown when a file or directory cannot be deleted.</li> * </ul> * * @param file file or directory to delete, can be {@code null} * @return {@code true} if the file or directory was deleted, otherwise * {@code false} * * @since 1.4 */ public static boolean deleteQuietly(final File file) { if (file == null) { return false; } try { if (file.isDirectory()) { cleanDirectory(file); } } catch (final Exception ignored) { } try { return file.delete(); } catch (final Exception ignored) { return false; } } /** * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory). * <p> * Files are normalized before comparison. * </p> * * Edge cases: * <ul> * <li>A {@code directory} must not be null: if null, throw IllegalArgumentException</li> * <li>A {@code directory} must be a directory: if not a directory, throw IllegalArgumentException</li> * <li>A directory does not contain itself: return false</li> * <li>A null child file is not contained in any parent: return false</li> * </ul> * * @param directory the file to consider as the parent. * @param child the file to consider as the child. * @return true is the candidate leaf is under by the specified composite. False otherwise. * @throws IOException if an IO error occurs while checking the files. * @throws IllegalArgumentException if {@code directory} is null or not a directory. * @see FilenameUtils#directoryContains(String, String) * @since 2.2 */ public static boolean directoryContains(final File directory, final File child) throws IOException { // Fail fast against NullPointerException if (directory == null) { throw new IllegalArgumentException("Directory must not be null"); } if (!directory.isDirectory()) { throw new IllegalArgumentException("Not a directory: " + directory); } if (child == null) { return false; } if (!directory.exists() || !child.exists()) { return false; } // Canonicalize paths (normalizes relative paths) final String canonicalParent = directory.getCanonicalPath(); final String canonicalChild = child.getCanonicalPath(); return FilenameUtils.directoryContains(canonicalParent, canonicalChild); } /** * Cleans a directory without deleting it. * * @param directory directory to clean * @throws IOException in case cleaning is unsuccessful * @throws IllegalArgumentException if {@code directory} does not exist or is not a directory */ public static void cleanDirectory(final File directory) throws IOException { final File[] files = verifiedListFiles(directory); IOException exception = null; for (final File file : files) { try { forceDelete(file); } catch (final IOException ioe) { exception = ioe; } } if (null != exception) { throw exception; } } /** * Lists files in a directory, asserting that the supplied directory satisfies exists and is a directory * @param directory The directory to list * @return The files in the directory, never null. * @throws IOException if an I/O error occurs */ private static File[] verifiedListFiles(final File directory) throws IOException { if (!directory.exists()) { final String message = directory + " does not exist"; throw new IllegalArgumentException(message); } if (!directory.isDirectory()) { final String message = directory + " is not a directory"; throw new IllegalArgumentException(message); } final File[] files = directory.listFiles(); if (files == null) { // null if security restricted throw new IOException("Failed to list contents of " + directory); } return files; } //----------------------------------------------------------------------- /** * Waits for NFS to propagate a file creation, imposing a timeout. * <p> * This method repeatedly tests {@link File#exists()} until it returns * true up to the maximum time specified in seconds. * * @param file the file to check, must not be {@code null} * @param seconds the maximum time in seconds to wait * @return true if file exists * @throws NullPointerException if the file is {@code null} */ public static boolean waitFor(final File file, final int seconds) { final long finishAt = System.currentTimeMillis() + (seconds * 1000L); boolean wasInterrupted = false; try { while (!file.exists()) { final long remaining = finishAt - System.currentTimeMillis(); if (remaining < 0){ return false; } try { Thread.sleep(Math.min(100, remaining)); } catch (final InterruptedException ignore) { wasInterrupted = true; } catch (final Exception ex) { break; } } } finally { if (wasInterrupted) { Thread.currentThread().interrupt(); } } return true; } //----------------------------------------------------------------------- /** * Reads the contents of a file into a String. * The file is always closed. * * @param file the file to read, must not be {@code null} * @param encoding the encoding to use, {@code null} means platform default * @return the file contents, never {@code null} * @throws IOException in case of an I/O error * @since 2.3 */ public static String readFileToString(final File file, final Charset encoding) throws IOException { try (InputStream in = openInputStream(file)) { return IOUtils.toString(in, Charsets.toCharset(encoding)); } } /** * Reads the contents of a file into a String. The file is always closed. * * @param file the file to read, must not be {@code null} * @param encoding the encoding to use, {@code null} means platform default * @return the file contents, never {@code null} * @throws IOException in case of an I/O error * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. * @since 2.3 */ public static String readFileToString(final File file, final String encoding) throws IOException { return readFileToString(file, Charsets.toCharset(encoding)); } /** * Reads the contents of a file into a String using the default encoding for the VM. * The file is always closed. * * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws IOException in case of an I/O error * @since 1.3.1 * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding) */ @Deprecated public static String readFileToString(final File file) throws IOException { return readFileToString(file, Charset.defaultCharset()); } /** * Reads the contents of a file into a byte array. * The file is always closed. * * @param file the file to read, must not be {@code null} * @return the file contents, never {@code null} * @throws IOException in case of an I/O error * @since 1.1 */ public static byte[] readFileToByteArray(final File file) throws IOException { try (InputStream in = openInputStream(file)) { final long fileLength = file.length(); // file.length() may return 0 for system-dependent entities, treat 0 as unknown length - see IO-453 return fileLength > 0 ? IOUtils.toByteArray(in, fileLength) : IOUtils.toByteArray(in); } } /** * Reads the contents of a file line by line to a List of Strings. * The file is always closed. * * @param file the file to read, must not be {@code null} * @param encoding the encoding to use, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws IOException in case of an I/O error * @since 2.3 */ public static List<String> readLines(final File file, final Charset encoding) throws IOException { try (InputStream in = openInputStream(file)) { return IOUtils.readLines(in, Charsets.toCharset(encoding)); } } /** * Reads the contents of a file line by line to a List of Strings. The file is always closed. * * @param file the file to read, must not be {@code null} * @param encoding the encoding to use, {@code null} means platform default * @return the list of Strings representing each line in the file, never {@code null} * @throws IOException in case of an I/O error * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported. * @since 1.1 */ public static List<String> readLines(final File file, final String encoding) throws IOException { return readLines(file, Charsets.toCharset(encoding)); } /** * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM. * The file is always closed. * * @param file the file to read, must not be {@code null} * @return the list of Strings representing each line in the file, never {@code null} * @throws IOException in case of an I/O error * @since 1.3 * @deprecated 2.5 use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding) */ @Deprecated public static List<String> readLines(final File file) throws IOException { return readLines(file, Charset.defaultCharset()); } /** * Returns an Iterator for the lines in a <code>File</code>. * <p> * This method opens an <code>InputStream</code> 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. * <p> * The recommended usage pattern is: * <pre> * LineIterator it = FileUtils.lineIterator(file, "UTF-8"); * try { * while (it.hasNext()) { * String line = it.nextLine(); * /// do something with line * } * } finally { * LineIterator.closeQuietly(iterator); * } * </pre> * <p> * If an exception occurs during the creation of the iterator, the * underlying stream is closed. * * @param file the file to open for input, must not be {@code null} * @param encoding the encoding to use, {@code null} means platform default * @return an Iterator of the lines in the file, never {@code null} * @throws IOException in case of an I/O error (file closed) * @since 1.2 */ public static LineIterator lineIterator(final File file, final String encoding) throws IOException { InputStream in = null; try { in = openInputStream(file); return IOUtils.lineIterator(in, encoding); } catch (final IOException | RuntimeException ex) { try { if (in != null) { in.close(); } } catch (final IOException e) { ex.addSuppressed(e); } throw ex; } } /** * Returns an Iterator for the lines in a <code>File</code> using the default encoding for the VM. * * @param file the file to open for input, must not be {@code null} * @return an Iterator of the lines in the file, never {@code null} * @throws IOException in case of an I/O error (file closed) * @see #lineIterator(File, String) * @since 1.3 */ public static LineIterator lineIterator(final File file) throws IOException { return lineIterator(file, null); } //----------------------------------------------------------------------- /** * Writes a String to a file creating the file if it does not exist. * <p> * NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 2.4 */ public static void writeStringToFile(final File file, final String data, final Charset encoding) throws IOException { writeStringToFile(file, data, encoding, false); } /** * Writes a String to a file creating the file if it does not exist. * <p> * NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM */ public static void writeStringToFile(final File file, final String data, final String encoding) throws IOException { writeStringToFile(file, data, encoding, false); } /** * Writes a String to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @param append if {@code true}, then the String will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.3 */ public static void writeStringToFile(final File file, final String data, final Charset encoding, final boolean append) throws IOException { try (OutputStream out = openOutputStream(file, append)) { IOUtils.write(data, out, encoding); } } /** * Writes a String to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @param append if {@code true}, then the String will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM * @since 2.1 */ public static void writeStringToFile(final File file, final String data, final String encoding, final boolean append) throws IOException { writeStringToFile(file, data, Charsets.toCharset(encoding), append); } /** * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. * * @param file the file to write * @param data the content to write to the file * @throws IOException in case of an I/O error * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding) */ @Deprecated public static void writeStringToFile(final File file, final String data) throws IOException { writeStringToFile(file, data, Charset.defaultCharset(), false); } /** * Writes a String to a file creating the file if it does not exist using the default encoding for the VM. * * @param file the file to write * @param data the content to write to the file * @param append if {@code true}, then the String will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.1 * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding) */ @Deprecated public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException { writeStringToFile(file, data, Charset.defaultCharset(), append); } /** * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. * * @param file the file to write * @param data the content to write to the file * @throws IOException in case of an I/O error * @since 2.0 * @deprecated 2.5 use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding) */ @Deprecated public static void write(final File file, final CharSequence data) throws IOException { write(file, data, Charset.defaultCharset(), false); } /** * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM. * * @param file the file to write * @param data the content to write to the file * @param append if {@code true}, then the data will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.1 * @deprecated 2.5 use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding) */ @Deprecated public static void write(final File file, final CharSequence data, final boolean append) throws IOException { write(file, data, Charset.defaultCharset(), append); } /** * Writes a CharSequence to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @throws IOException in case of an I/O error * @since 2.3 */ public static void write(final File file, final CharSequence data, final Charset encoding) throws IOException { write(file, data, encoding, false); } /** * Writes a CharSequence to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 2.0 */ public static void write(final File file, final CharSequence data, final String encoding) throws IOException { write(file, data, encoding, false); } /** * Writes a CharSequence to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @param append if {@code true}, then the data will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.3 */ public static void write(final File file, final CharSequence data, final Charset encoding, final boolean append) throws IOException { final String str = data == null ? null : data.toString(); writeStringToFile(file, str, encoding, append); } /** * Writes a CharSequence to a file creating the file if it does not exist. * * @param file the file to write * @param data the content to write to the file * @param encoding the encoding to use, {@code null} means platform default * @param append if {@code true}, then the data will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.nio.charset.UnsupportedCharsetException thrown instead of {@link java.io * .UnsupportedEncodingException} in version 2.2 if the encoding is not supported by the VM * @since 2.1 */ public static void write(final File file, final CharSequence data, final String encoding, final boolean append) throws IOException { write(file, data, Charsets.toCharset(encoding), append); } /** * Writes a byte array to a file creating the file if it does not exist. * <p> * NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. * * @param file the file to write to * @param data the content to write to the file * @throws IOException in case of an I/O error * @since 1.1 */ public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException { writeByteArrayToFile(file, data, false); } /** * Writes a byte array to a file creating the file if it does not exist. * * @param file the file to write to * @param data the content to write to the file * @param append if {@code true}, then bytes will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.1 */ public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException { writeByteArrayToFile(file, data, 0, data.length, append); } /** * Writes {@code len} bytes from the specified byte array starting * at offset {@code off} to a file, creating the file if it does * not exist. * * @param file the file to write to * @param data the content to write to the file * @param off the start offset in the data * @param len the number of bytes to write * @throws IOException in case of an I/O error * @since 2.5 */ public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException { writeByteArrayToFile(file, data, off, len, false); } /** * Writes {@code len} bytes from the specified byte array starting * at offset {@code off} to a file, creating the file if it does * not exist. * * @param file the file to write to * @param data the content to write to the file * @param off the start offset in the data * @param len the number of bytes to write * @param append if {@code true}, then bytes will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.5 */ public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException { try (OutputStream out = openOutputStream(file, append)) { out.write(data, off, len); } } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The specified character encoding and the default line ending will be used. * <p> * NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. * * @param file the file to write to * @param encoding the encoding to use, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 1.1 */ public static void writeLines(final File file, final String encoding, final Collection<?> lines) throws IOException { writeLines(file, encoding, lines, null, false); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line, optionally appending. * The specified character encoding and the default line ending will be used. * * @param file the file to write to * @param encoding the encoding to use, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 2.1 */ public static void writeLines(final File file, final String encoding, final Collection<?> lines, final boolean append) throws IOException { writeLines(file, encoding, lines, null, append); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The default VM encoding and the default line ending will be used. * * @param file the file to write to * @param lines the lines to write, {@code null} entries produce blank lines * @throws IOException in case of an I/O error * @since 1.3 */ public static void writeLines(final File file, final Collection<?> lines) throws IOException { writeLines(file, null, lines, null, false); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The default VM encoding and the default line ending will be used. * * @param file the file to write to * @param lines the lines to write, {@code null} entries produce blank lines * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.1 */ public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException { writeLines(file, null, lines, null, append); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The specified character encoding and the line ending will be used. * <p> * NOTE: As from v1.3, the parent directories of the file will be created * if they do not exist. * * @param file the file to write to * @param encoding the encoding to use, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 1.1 */ public static void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding) throws IOException { writeLines(file, encoding, lines, lineEnding, false); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The specified character encoding and the line ending will be used. * * @param file the file to write to * @param encoding the encoding to use, {@code null} means platform default * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM * @since 2.1 */ public static void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException { try (OutputStream out = new BufferedOutputStream(openOutputStream(file, append))) { IOUtils.writeLines(lines, lineEnding, out, encoding); } } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The default VM encoding and the specified line ending will be used. * * @param file the file to write to * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @throws IOException in case of an I/O error * @since 1.3 */ public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException { writeLines(file, null, lines, lineEnding, false); } /** * Writes the <code>toString()</code> value of each item in a collection to * the specified <code>File</code> line by line. * The default VM encoding and the specified line ending will be used. * * @param file the file to write to * @param lines the lines to write, {@code null} entries produce blank lines * @param lineEnding the line separator to use, {@code null} is system default * @param append if {@code true}, then the lines will be added to the * end of the file rather than overwriting * @throws IOException in case of an I/O error * @since 2.1 */ public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException { writeLines(file, null, lines, lineEnding, append); } //----------------------------------------------------------------------- /** * Deletes a file. If file is a directory, delete it and all sub-directories. * <p> * The difference between File.delete() and this method are: * <ul> * <li>A directory to be deleted does not have to be empty.</li> * <li>You get exceptions when a file or directory cannot be deleted. * (java.io.File methods returns a boolean)</li> * </ul> * * @param file file or directory to delete, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws FileNotFoundException if the file was not found * @throws IOException in case deletion is unsuccessful */ public static void forceDelete(final File file) throws IOException { if (file.isDirectory()) { deleteDirectory(file); } else { final boolean filePresent = file.exists(); if (!file.delete()) { if (!filePresent) { throw new FileNotFoundException("File does not exist: " + file); } final String message = "Unable to delete file: " + file; throw new IOException(message); } } } /** * Schedules a file to be deleted when JVM exits. * If file is directory delete it and all sub-directories. * * @param file file or directory to delete, must not be {@code null} * @throws NullPointerException if the file is {@code null} * @throws IOException in case deletion is unsuccessful */ public static void forceDeleteOnExit(final File file) throws IOException { if (file.isDirectory()) { deleteDirectoryOnExit(file); } else { file.deleteOnExit(); } } /** * 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); } } /** * Cleans a directory without deleting it. * * @param directory directory to clean, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws IOException in case cleaning is unsuccessful */ private static void cleanDirectoryOnExit(final File directory) throws IOException { final File[] files = verifiedListFiles(directory); IOException exception = null; for (final File file : files) { try { forceDeleteOnExit(file); } catch (final IOException ioe) { exception = ioe; } } if (null != exception) { throw exception; } } /** * Makes a directory, including any necessary but nonexistent parent * directories. If a file already exists with specified name but it is * not a directory then an IOException is thrown. * If the directory cannot be created (or does not already exist) * then an IOException is thrown. * * @param directory directory to create, must not be {@code null} * @throws NullPointerException if the directory is {@code null} * @throws IOException if the directory cannot be created or the file already exists but is not a directory */ public static void forceMkdir(final File directory) throws IOException { if (directory.exists()) { if (!directory.isDirectory()) { final String message = "File " + directory + " exists and is " + "not a directory. Unable to create directory."; throw new IOException(message); } } else { if (!directory.mkdirs()) { // Double-check that some other thread or process hasn't made // the directory in the background if (!directory.isDirectory()) { final String message = "Unable to create directory " + directory; throw new IOException(message); } } } } /** * Makes any necessary but nonexistent parent directories for a given File. If the parent directory cannot be * created then an IOException is thrown. * * @param file file with parent to create, must not be {@code null} * @throws NullPointerException if the file is {@code null} * @throws IOException if the parent directory cannot be created * @since 2.5 */ public static void forceMkdirParent(final File file) throws IOException { final File parent = file.getParentFile(); if (parent == null) { return; } forceMkdir(parent); } //----------------------------------------------------------------------- /** * Returns the size of the specified file or directory. If the provided * {@link File} is a regular file, then the file's length is returned. * If the argument is a directory, then the size of the directory is * calculated recursively. If a directory or subdirectory is security * restricted, its size will not be included. * <p> * 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. * * @param file the regular file or directory to return the size * of (must not be {@code null}). * * @return the length of the file, or recursive size of the directory, * provided (in bytes). * * @throws NullPointerException if the file is {@code null} * @throws IllegalArgumentException if the file does not exist. * * @since 2.0 */ public static long sizeOf(final File file) { if (!file.exists()) { final String message = file + " does not exist"; throw new IllegalArgumentException(message); } if (file.isDirectory()) { return sizeOfDirectory0(file); // private method; expects directory } else { return file.length(); } } /** * Returns the size of the specified file or directory. If the provided * {@link File} is a regular file, then the file's length is returned. * If the argument is a directory, then the size of the directory is * calculated recursively. If a directory or subdirectory is security * restricted, its size will not be included. * * @param file the regular file or directory to return the size * of (must not be {@code null}). * * @return the length of the file, or recursive size of the directory, * provided (in bytes). * * @throws NullPointerException if the file is {@code null} * @throws IllegalArgumentException if the file does not exist. * * @since 2.4 */ public static BigInteger sizeOfAsBigInteger(final File file) { if (!file.exists()) { final String message = file + " does not exist"; throw new IllegalArgumentException(message); } if (file.isDirectory()) { return sizeOfDirectoryBig0(file); // internal method } else { return BigInteger.valueOf(file.length()); } } /** * Counts the size of a directory recursively (sum of the length of all files). * <p> * 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. * * @param directory directory to inspect, must not be {@code null} * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total * is greater than {@link Long#MAX_VALUE}. * @throws NullPointerException if the directory is {@code null} */ public static long sizeOfDirectory(final File directory) { checkDirectory(directory); return sizeOfDirectory0(directory); } // Private method, must be invoked will a directory parameter /** * the size of a director * @param directory the directory to check * @return the size */ private static long sizeOfDirectory0(final File directory) { final File[] files = directory.listFiles(); if (files == null) { // null if security restricted return 0L; } long size = 0; for (final File file : files) { try { if (!isSymlink(file)) { size += sizeOf0(file); // internal method if (size < 0) { break; } } } catch (final IOException ioe) { // Ignore exceptions caught when asking if a File is a symlink. } } return size; } // Internal method - does not check existence /** * the size of a file * @param file the file to check * @return the size of the file */ private static long sizeOf0(final File file) { if (file.isDirectory()) { return sizeOfDirectory0(file); } else { return file.length(); // will be 0 if file does not exist } } /** * Counts the size of a directory recursively (sum of the length of all files). * * @param directory directory to inspect, must not be {@code null} * @return size of directory in bytes, 0 if directory is security restricted. * @throws NullPointerException if the directory is {@code null} * @since 2.4 */ public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) { checkDirectory(directory); return sizeOfDirectoryBig0(directory); } // Must be called with a directory /** * Finds the size of a directory * * @param directory The directory * @return the size */ private static BigInteger sizeOfDirectoryBig0(final File directory) { final File[] files = directory.listFiles(); if (files == null) { // null if security restricted return BigInteger.ZERO; } BigInteger size = BigInteger.ZERO; for (final File file : files) { try { if (!isSymlink(file)) { size = size.add(sizeOfBig0(file)); } } catch (final IOException ioe) { // Ignore exceptions caught when asking if a File is a symlink. } } return size; } // internal method; if file does not exist will return 0 /** * Returns the size of a file * @param fileOrDir The file * @return the size */ private static BigInteger sizeOfBig0(final File fileOrDir) { if (fileOrDir.isDirectory()) { return sizeOfDirectoryBig0(fileOrDir); } else { return BigInteger.valueOf(fileOrDir.length()); } } /** * Checks that the given {@code File} exists and is a directory. * * @param directory The {@code File} to check. * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory. */ private static void checkDirectory(final File directory) { if (!directory.exists()) { throw new IllegalArgumentException(directory + " does not exist"); } if (!directory.isDirectory()) { throw new IllegalArgumentException(directory + " is not a directory"); } } //----------------------------------------------------------------------- /** * Tests if the specified <code>File</code> is newer than the reference * <code>File</code>. * * @param file the <code>File</code> of which the modification date must * be compared, must not be {@code null} * @param reference the <code>File</code> of which the modification date * is used, must not be {@code null} * @return true if the <code>File</code> exists and has been modified more * recently than the reference <code>File</code> * @throws IllegalArgumentException if the file is {@code null} * @throws IllegalArgumentException if the reference file is {@code null} or doesn't exist */ public static boolean isFileNewer(final File file, final File reference) { if (reference == null) { throw new IllegalArgumentException("No specified reference file"); } if (!reference.exists()) { throw new IllegalArgumentException("The reference file '" + reference + "' doesn't exist"); } return isFileNewer(file, reference.lastModified()); } /** * Tests if the specified <code>File</code> is newer than the specified * <code>Date</code>. * * @param file the <code>File</code> of which the modification date * must be compared, must not be {@code null} * @param date the date reference, must not be {@code null} * @return true if the <code>File</code> exists and has been modified * after the given <code>Date</code>. * @throws IllegalArgumentException if the file is {@code null} * @throws IllegalArgumentException if the date is {@code null} */ public static boolean isFileNewer(final File file, final Date date) { if (date == null) { throw new IllegalArgumentException("No specified date"); } return isFileNewer(file, date.getTime()); } /** * Tests if the specified <code>File</code> is newer than the specified * time reference. * * @param file the <code>File</code> of which the modification date must * be compared, must not be {@code null} * @param timeMillis the time reference measured in milliseconds since the * epoch (00:00:00 GMT, January 1, 1970) * @return true if the <code>File</code> exists and has been modified after * the given time reference. * @throws IllegalArgumentException if the file is {@code null} */ public static boolean isFileNewer(final File file, final long timeMillis) { if (file == null) { throw new IllegalArgumentException("No specified file"); } if (!file.exists()) { return false; } return file.lastModified() > timeMillis; } //----------------------------------------------------------------------- /** * Tests if the specified <code>File</code> is older than the reference * <code>File</code>. * * @param file the <code>File</code> of which the modification date must * be compared, must not be {@code null} * @param reference the <code>File</code> of which the modification date * is used, must not be {@code null} * @return true if the <code>File</code> exists and has been modified before * the reference <code>File</code> * @throws IllegalArgumentException if the file is {@code null} * @throws IllegalArgumentException if the reference file is {@code null} or doesn't exist */ public static boolean isFileOlder(final File file, final File reference) { if (reference == null) { throw new IllegalArgumentException("No specified reference file"); } if (!reference.exists()) { throw new IllegalArgumentException("The reference file '" + reference + "' doesn't exist"); } return isFileOlder(file, reference.lastModified()); } /** * Tests if the specified <code>File</code> is older than the specified * <code>Date</code>. * * @param file the <code>File</code> of which the modification date * must be compared, must not be {@code null} * @param date the date reference, must not be {@code null} * @return true if the <code>File</code> exists and has been modified * before the given <code>Date</code>. * @throws IllegalArgumentException if the file is {@code null} * @throws IllegalArgumentException if the date is {@code null} */ public static boolean isFileOlder(final File file, final Date date) { if (date == null) { throw new IllegalArgumentException("No specified date"); } return isFileOlder(file, date.getTime()); } /** * Tests if the specified <code>File</code> is older than the specified * time reference. * * @param file the <code>File</code> of which the modification date must * be compared, must not be {@code null} * @param timeMillis the time reference measured in milliseconds since the * epoch (00:00:00 GMT, January 1, 1970) * @return true if the <code>File</code> exists and has been modified before * the given time reference. * @throws IllegalArgumentException if the file is {@code null} */ public static boolean isFileOlder(final File file, final long timeMillis) { if (file == null) { throw new IllegalArgumentException("No specified file"); } if (!file.exists()) { return false; } return file.lastModified() < timeMillis; } //----------------------------------------------------------------------- /** * 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 file or checksum is {@code null} * @throws IllegalArgumentException if the file is a directory * @throws IOException if an IO error occurs reading the file * @since 1.3 */ public static long checksumCRC32(final File file) throws IOException { final CRC32 crc = new CRC32(); checksum(file, crc); return crc.getValue(); } /** * Computes the checksum of a file using the specified checksum object. * Multiple files may be checked using one <code>Checksum</code> instance * if desired simply by reusing the same checksum object. * For example: * <pre> * long csum = FileUtils.checksum(file, new CRC32()).getValue(); * </pre> * * @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 file or checksum is {@code null} * @throws IllegalArgumentException if the file is a directory * @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 { if (file.isDirectory()) { throw new IllegalArgumentException("Checksums can't be computed on directories"); } try (InputStream in = new CheckedInputStream(new FileInputStream(file), checksum)) { IOUtils.copy(in, new NullOutputStream()); } return checksum; } /** * Moves a directory. * <p> * When the destination directory is on another file system, do a "copy and delete". * * @param srcDir the directory to be moved * @param destDir the destination directory * @throws NullPointerException if source or destination is {@code null} * @throws FileExistsException if the destination directory exists * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs moving the file * @since 1.4 */ public static void moveDirectory(final File srcDir, final File destDir) throws IOException { if (srcDir == null) { throw new NullPointerException("Source must not be null"); } if (destDir == null) { throw new NullPointerException("Destination must not be null"); } if (!srcDir.exists()) { throw new FileNotFoundException("Source '" + srcDir + "' does not exist"); } if (!srcDir.isDirectory()) { throw new IOException("Source '" + srcDir + "' is not a directory"); } if (destDir.exists()) { throw new FileExistsException("Destination '" + destDir + "' already exists"); } final boolean rename = srcDir.renameTo(destDir); if (!rename) { if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) { throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir); } copyDirectory(srcDir, destDir); deleteDirectory(srcDir); if (srcDir.exists()) { throw new IOException("Failed to delete original directory '" + srcDir + "' after copy to '" + destDir + "'"); } } } /** * Moves a directory to another directory. * * @param src the file to be moved * @param destDir the destination file * @param createDestDir If {@code true} create the destination directory, * otherwise if {@code false} throw an IOException * @throws NullPointerException if source or destination is {@code null} * @throws FileExistsException if the directory exists in the destination directory * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs moving the file * @since 1.4 */ public static void moveDirectoryToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException { if (src == null) { throw new NullPointerException("Source must not be null"); } if (destDir == null) { throw new NullPointerException("Destination directory must not be null"); } if (!destDir.exists() && createDestDir) { destDir.mkdirs(); } if (!destDir.exists()) { throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + createDestDir + "]"); } if (!destDir.isDirectory()) { throw new IOException("Destination '" + destDir + "' is not a directory"); } moveDirectory(src, new File(destDir, src.getName())); } /** * Moves a file. * <p> * When the destination file is on another file system, do a "copy and delete". * * @param srcFile the file to be moved * @param destFile the destination file * @throws NullPointerException if source or destination is {@code null} * @throws FileExistsException if the destination file exists * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs moving the file * @since 1.4 */ public static void moveFile(final File srcFile, final File destFile) throws IOException { if (srcFile == null) { throw new NullPointerException("Source must not be null"); } if (destFile == null) { throw new NullPointerException("Destination must not be null"); } if (!srcFile.exists()) { throw new FileNotFoundException("Source '" + srcFile + "' does not exist"); } if (srcFile.isDirectory()) { throw new IOException("Source '" + srcFile + "' is a directory"); } if (destFile.exists()) { throw new FileExistsException("Destination '" + destFile + "' already exists"); } if (destFile.isDirectory()) { throw new IOException("Destination '" + destFile + "' is a directory"); } final boolean rename = srcFile.renameTo(destFile); if (!rename) { copyFile(srcFile, destFile); if (!srcFile.delete()) { FileUtils.deleteQuietly(destFile); throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'"); } } } /** * Moves a file to a directory. * * @param srcFile the file to be moved * @param destDir the destination file * @param createDestDir If {@code true} create the destination directory, * otherwise if {@code false} throw an IOException * @throws NullPointerException if source or destination is {@code null} * @throws FileExistsException if the destination file exists * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs moving the file * @since 1.4 */ public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException { if (srcFile == null) { throw new NullPointerException("Source must not be null"); } if (destDir == null) { throw new NullPointerException("Destination directory must not be null"); } if (!destDir.exists() && createDestDir) { destDir.mkdirs(); } if (!destDir.exists()) { throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + createDestDir + "]"); } if (!destDir.isDirectory()) { throw new IOException("Destination '" + destDir + "' is not a directory"); } moveFile(srcFile, new File(destDir, srcFile.getName())); } /** * Moves a file or directory to the destination directory. * <p> * When the destination is on another file system, do a "copy and delete". * * @param src the file or directory to be moved * @param destDir the destination directory * @param createDestDir If {@code true} create the destination directory, * otherwise if {@code false} throw an IOException * @throws NullPointerException if source or destination is {@code null} * @throws FileExistsException if the directory or file exists in the destination directory * @throws IOException if source or destination is invalid * @throws IOException if an IO error occurs moving the file * @since 1.4 */ public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException { if (src == null) { throw new NullPointerException("Source must not be null"); } if (destDir == null) { throw new NullPointerException("Destination must not be null"); } if (!src.exists()) { throw new FileNotFoundException("Source '" + src + "' does not exist"); } if (src.isDirectory()) { moveDirectoryToDirectory(src, destDir, createDestDir); } else { moveFileToDirectory(src, destDir, createDestDir); } } /** * Determines whether the specified file is a Symbolic Link rather than an actual file. * <p> * Will not return true if there is a Symbolic Link anywhere in the path, * only if the specific file is. * <p> * When using jdk1.7, this method delegates to {@code boolean java.nio.file.Files.isSymbolicLink(Path path)} * * <b>Note:</b> the current implementation always returns {@code false} if running on * jkd1.6 and the system is detected as Windows using {@link FilenameUtils#isSystemWindows()} * <p> * For code that runs on Java 1.7 or later, use the following method instead: * <br> * {@code boolean java.nio.file.Files.isSymbolicLink(Path path)} * @param file the file to check * @return true if the file is a Symbolic Link * @throws IOException if an IO error occurs while checking the file * @since 2.0 */ public static boolean isSymlink(final File file) throws IOException { if (file == null) { throw new NullPointerException("File must not be null"); } return Files.isSymbolicLink(file.toPath()); } }
⏎ org/apache/commons/io/FileUtils.java
Or download all of them as a single archive file:
File name: commons-io-2.6-sources.jar File size: 280834 bytes Release date: 2017-10-05 Download
⇒ Download and Install commons-io-2.5-bin.zip
2020-12-09, 61563👍, 1💬
Popular Posts:
What Is commons-codec-1.4.jar? commons-codec-1.4.jar is the JAR file for Apache Commons Codec 1.4, w...
JDK 11 java.security.jgss.jmod is the JMOD file for JDK 11 Security JGSS (Java Generic Security Serv...
JRE 8 deploy.jar is the JAR file for JRE 8 Java Control Panel and other deploy tools. JRE (Java Runt...
JDK 11 jdk.crypto.mscapi.jmod is the JMOD file for JDK 11 Crypto MSCAPI module. JDK 11 Crypto MSCAPI...
maven-core-3.8.6.jar is the JAR file for Apache Maven 3.8.6 Core module. Apache Maven is a software ...