View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.io;
18  
19  import java.io.BufferedOutputStream;
20  import java.io.File;
21  import java.io.FileFilter;
22  import java.io.FileInputStream;
23  import java.io.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.io.OutputStream;
29  import java.io.Reader;
30  import java.io.UnsupportedEncodingException;
31  import java.math.BigInteger;
32  import java.net.URL;
33  import java.net.URLConnection;
34  import java.nio.ByteBuffer;
35  import java.nio.channels.FileChannel;
36  import java.nio.charset.Charset;
37  import java.nio.charset.UnsupportedCharsetException;
38  import java.util.ArrayList;
39  import java.util.Collection;
40  import java.util.Date;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.util.zip.CRC32;
44  import java.util.zip.CheckedInputStream;
45  import java.util.zip.Checksum;
46  
47  import org.apache.commons.io.filefilter.DirectoryFileFilter;
48  import org.apache.commons.io.filefilter.FalseFileFilter;
49  import org.apache.commons.io.filefilter.FileFilterUtils;
50  import org.apache.commons.io.filefilter.IOFileFilter;
51  import org.apache.commons.io.filefilter.SuffixFileFilter;
52  import org.apache.commons.io.filefilter.TrueFileFilter;
53  import org.apache.commons.io.output.NullOutputStream;
54  
55  /**
56   * General file manipulation utilities.
57   * <p>
58   * Facilities are provided in the following areas:
59   * <ul>
60   * <li>writing to a file
61   * <li>reading from a file
62   * <li>make a directory including parent directories
63   * <li>copying files and directories
64   * <li>deleting files and directories
65   * <li>converting to and from a URL
66   * <li>listing files and directories by filter and extension
67   * <li>comparing file content
68   * <li>file last changed date
69   * <li>calculating a checksum
70   * </ul>
71   * <p>
72   * Origin of code: Excalibur, Alexandria, Commons-Utils
73   *
74   * @version $Id: FileUtils.java 1565317 2014-02-06 16:02:20Z ggregory $
75   */
76  public class FileUtils {
77  
78      /**
79       * Instances should NOT be constructed in standard programming.
80       */
81      public FileUtils() {
82          super();
83      }
84  
85      /**
86       * The number of bytes in a kilobyte.
87       */
88      public static final long ONE_KB = 1024;
89  
90      /**
91       * The number of bytes in a kilobyte.
92       *
93       * @since 2.4
94       */
95      public static final BigInteger ONE_KB_BI = BigInteger.valueOf(ONE_KB);
96  
97      /**
98       * The number of bytes in a megabyte.
99       */
100     public static final long ONE_MB = ONE_KB * ONE_KB;
101 
102     /**
103      * The number of bytes in a megabyte.
104      *
105      * @since 2.4
106      */
107     public static final BigInteger ONE_MB_BI = ONE_KB_BI.multiply(ONE_KB_BI);
108 
109     /**
110      * The file copy buffer size (30 MB)
111      */
112     private static final long FILE_COPY_BUFFER_SIZE = ONE_MB * 30;
113 
114     /**
115      * The number of bytes in a gigabyte.
116      */
117     public static final long ONE_GB = ONE_KB * ONE_MB;
118 
119     /**
120      * The number of bytes in a gigabyte.
121      *
122      * @since 2.4
123      */
124     public static final BigInteger ONE_GB_BI = ONE_KB_BI.multiply(ONE_MB_BI);
125 
126     /**
127      * The number of bytes in a terabyte.
128      */
129     public static final long ONE_TB = ONE_KB * ONE_GB;
130 
131     /**
132      * The number of bytes in a terabyte.
133      *
134      * @since 2.4
135      */
136     public static final BigInteger ONE_TB_BI = ONE_KB_BI.multiply(ONE_GB_BI);
137 
138     /**
139      * The number of bytes in a petabyte.
140      */
141     public static final long ONE_PB = ONE_KB * ONE_TB;
142 
143     /**
144      * The number of bytes in a petabyte.
145      *
146      * @since 2.4
147      */
148     public static final BigInteger ONE_PB_BI = ONE_KB_BI.multiply(ONE_TB_BI);
149 
150     /**
151      * The number of bytes in an exabyte.
152      */
153     public static final long ONE_EB = ONE_KB * ONE_PB;
154 
155     /**
156      * The number of bytes in an exabyte.
157      *
158      * @since 2.4
159      */
160     public static final BigInteger ONE_EB_BI = ONE_KB_BI.multiply(ONE_PB_BI);
161 
162     /**
163      * The number of bytes in a zettabyte.
164      */
165     public static final BigInteger ONE_ZB = BigInteger.valueOf(ONE_KB).multiply(BigInteger.valueOf(ONE_EB));
166 
167     /**
168      * The number of bytes in a yottabyte.
169      */
170     public static final BigInteger ONE_YB = ONE_KB_BI.multiply(ONE_ZB);
171 
172     /**
173      * An empty array of type <code>File</code>.
174      */
175     public static final File[] EMPTY_FILE_ARRAY = new File[0];
176 
177     //-----------------------------------------------------------------------
178     /**
179      * Construct a file from the set of name elements.
180      *
181      * @param directory the parent directory
182      * @param names the name elements
183      * @return the file
184      * @since 2.1
185      */
186     public static File getFile(final File directory, final String... names) {
187         if (directory == null) {
188             throw new NullPointerException("directorydirectory must not be null");
189         }
190         if (names == null) {
191             throw new NullPointerException("names must not be null");
192         }
193         File file = directory;
194         for (final String name : names) {
195             file = new File(file, name);
196         }
197         return file;
198     }
199 
200     /**
201      * Construct a file from the set of name elements.
202      *
203      * @param names the name elements
204      * @return the file
205      * @since 2.1
206      */
207     public static File getFile(final String... names) {
208         if (names == null) {
209             throw new NullPointerException("names must not be null");
210         }
211         File file = null;
212         for (final String name : names) {
213             if (file == null) {
214                 file = new File(name);
215             } else {
216                 file = new File(file, name);
217             }
218         }
219         return file;
220     }
221 
222     /**
223      * Returns the path to the system temporary directory.
224      *
225      * @return the path to the system temporary directory.
226      *
227      * @since 2.0
228      */
229     public static String getTempDirectoryPath() {
230         return System.getProperty("java.io.tmpdir");
231     }
232 
233     /**
234      * Returns a {@link File} representing the system temporary directory.
235      *
236      * @return the system temporary directory.
237      *
238      * @since 2.0
239      */
240     public static File getTempDirectory() {
241         return new File(getTempDirectoryPath());
242     }
243 
244     /**
245      * Returns the path to the user's home directory.
246      *
247      * @return the path to the user's home directory.
248      *
249      * @since 2.0
250      */
251     public static String getUserDirectoryPath() {
252         return System.getProperty("user.home");
253     }
254 
255     /**
256      * Returns a {@link File} representing the user's home directory.
257      *
258      * @return the user's home directory.
259      *
260      * @since 2.0
261      */
262     public static File getUserDirectory() {
263         return new File(getUserDirectoryPath());
264     }
265 
266     //-----------------------------------------------------------------------
267     /**
268      * Opens a {@link FileInputStream} for the specified file, providing better
269      * error messages than simply calling <code>new FileInputStream(file)</code>.
270      * <p>
271      * At the end of the method either the stream will be successfully opened,
272      * or an exception will have been thrown.
273      * <p>
274      * An exception is thrown if the file does not exist.
275      * An exception is thrown if the file object exists but is a directory.
276      * An exception is thrown if the file exists but cannot be read.
277      *
278      * @param file  the file to open for input, must not be {@code null}
279      * @return a new {@link FileInputStream} for the specified file
280      * @throws FileNotFoundException if the file does not exist
281      * @throws IOException if the file object is a directory
282      * @throws IOException if the file cannot be read
283      * @since 1.3
284      */
285     public static FileInputStream openInputStream(final File file) throws IOException {
286         if (file.exists()) {
287             if (file.isDirectory()) {
288                 throw new IOException("File '" + file + "' exists but is a directory");
289             }
290             if (file.canRead() == false) {
291                 throw new IOException("File '" + file + "' cannot be read");
292             }
293         } else {
294             throw new FileNotFoundException("File '" + file + "' does not exist");
295         }
296         return new FileInputStream(file);
297     }
298 
299     //-----------------------------------------------------------------------
300     /**
301      * Opens a {@link FileOutputStream} for the specified file, checking and
302      * creating the parent directory if it does not exist.
303      * <p>
304      * At the end of the method either the stream will be successfully opened,
305      * or an exception will have been thrown.
306      * <p>
307      * The parent directory will be created if it does not exist.
308      * The file will be created if it does not exist.
309      * An exception is thrown if the file object exists but is a directory.
310      * An exception is thrown if the file exists but cannot be written to.
311      * An exception is thrown if the parent directory cannot be created.
312      *
313      * @param file  the file to open for output, must not be {@code null}
314      * @return a new {@link FileOutputStream} for the specified file
315      * @throws IOException if the file object is a directory
316      * @throws IOException if the file cannot be written to
317      * @throws IOException if a parent directory needs creating but that fails
318      * @since 1.3
319      */
320     public static FileOutputStream openOutputStream(final File file) throws IOException {
321         return openOutputStream(file, false);
322     }
323 
324     /**
325      * Opens a {@link FileOutputStream} for the specified file, checking and
326      * creating the parent directory if it does not exist.
327      * <p>
328      * At the end of the method either the stream will be successfully opened,
329      * or an exception will have been thrown.
330      * <p>
331      * The parent directory will be created if it does not exist.
332      * The file will be created if it does not exist.
333      * An exception is thrown if the file object exists but is a directory.
334      * An exception is thrown if the file exists but cannot be written to.
335      * An exception is thrown if the parent directory cannot be created.
336      *
337      * @param file  the file to open for output, must not be {@code null}
338      * @param append if {@code true}, then bytes will be added to the
339      * end of the file rather than overwriting
340      * @return a new {@link FileOutputStream} for the specified file
341      * @throws IOException if the file object is a directory
342      * @throws IOException if the file cannot be written to
343      * @throws IOException if a parent directory needs creating but that fails
344      * @since 2.1
345      */
346     public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {
347         if (file.exists()) {
348             if (file.isDirectory()) {
349                 throw new IOException("File '" + file + "' exists but is a directory");
350             }
351             if (file.canWrite() == false) {
352                 throw new IOException("File '" + file + "' cannot be written to");
353             }
354         } else {
355             final File parent = file.getParentFile();
356             if (parent != null) {
357                 if (!parent.mkdirs() && !parent.isDirectory()) {
358                     throw new IOException("Directory '" + parent + "' could not be created");
359                 }
360             }
361         }
362         return new FileOutputStream(file, append);
363     }
364 
365     //-----------------------------------------------------------------------
366     /**
367      * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
368      * <p>
369      * 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
370      * nearest GB boundary.
371      * </p>
372      * <p>
373      * Similarly for the 1MB and 1KB boundaries.
374      * </p>
375      *
376      * @param size
377      *            the number of bytes
378      * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
379      * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
380      * @since 2.4
381      */
382     // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
383     public static String byteCountToDisplaySize(final BigInteger size) {
384         String displaySize;
385 
386         if (size.divide(ONE_EB_BI).compareTo(BigInteger.ZERO) > 0) {
387             displaySize = String.valueOf(size.divide(ONE_EB_BI)) + " EB";
388         } else if (size.divide(ONE_PB_BI).compareTo(BigInteger.ZERO) > 0) {
389             displaySize = String.valueOf(size.divide(ONE_PB_BI)) + " PB";
390         } else if (size.divide(ONE_TB_BI).compareTo(BigInteger.ZERO) > 0) {
391             displaySize = String.valueOf(size.divide(ONE_TB_BI)) + " TB";
392         } else if (size.divide(ONE_GB_BI).compareTo(BigInteger.ZERO) > 0) {
393             displaySize = String.valueOf(size.divide(ONE_GB_BI)) + " GB";
394         } else if (size.divide(ONE_MB_BI).compareTo(BigInteger.ZERO) > 0) {
395             displaySize = String.valueOf(size.divide(ONE_MB_BI)) + " MB";
396         } else if (size.divide(ONE_KB_BI).compareTo(BigInteger.ZERO) > 0) {
397             displaySize = String.valueOf(size.divide(ONE_KB_BI)) + " KB";
398         } else {
399             displaySize = String.valueOf(size) + " bytes";
400         }
401         return displaySize;
402     }
403 
404     /**
405      * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
406      * <p>
407      * 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
408      * nearest GB boundary.
409      * </p>
410      * <p>
411      * Similarly for the 1MB and 1KB boundaries.
412      * </p>
413      *
414      * @param size
415      *            the number of bytes
416      * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
417      * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
418      */
419     // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
420     public static String byteCountToDisplaySize(final long size) {
421         return byteCountToDisplaySize(BigInteger.valueOf(size));
422     }
423 
424     //-----------------------------------------------------------------------
425     /**
426      * Implements the same behaviour as the "touch" utility on Unix. It creates
427      * a new file with size 0 or, if the file exists already, it is opened and
428      * closed without modifying it, but updating the file date and time.
429      * <p>
430      * NOTE: As from v1.3, this method throws an IOException if the last
431      * modified date of the file cannot be set. Also, as from v1.3 this method
432      * creates parent directories if they do not exist.
433      *
434      * @param file  the File to touch
435      * @throws IOException If an I/O problem occurs
436      */
437     public static void touch(final File file) throws IOException {
438         if (!file.exists()) {
439             final OutputStream out = openOutputStream(file);
440             IOUtils.closeQuietly(out);
441         }
442         final boolean success = file.setLastModified(System.currentTimeMillis());
443         if (!success) {
444             throw new IOException("Unable to set the last modification time for " + file);
445         }
446     }
447 
448     //-----------------------------------------------------------------------
449     /**
450      * Converts a Collection containing java.io.File instanced into array
451      * representation. This is to account for the difference between
452      * File.listFiles() and FileUtils.listFiles().
453      *
454      * @param files  a Collection containing java.io.File instances
455      * @return an array of java.io.File
456      */
457     public static File[] convertFileCollectionToFileArray(final Collection<File> files) {
458          return files.toArray(new File[files.size()]);
459     }
460 
461     //-----------------------------------------------------------------------
462     /**
463      * Finds files within a given directory (and optionally its
464      * subdirectories). All files found are filtered by an IOFileFilter.
465      *
466      * @param files the collection of files found.
467      * @param directory the directory to search in.
468      * @param filter the filter to apply to files and directories.
469      * @param includeSubDirectories indicates if will include the subdirectories themselves
470      */
471     private static void innerListFiles(final Collection<File> files, final File directory,
472             final IOFileFilter filter, final boolean includeSubDirectories) {
473         final File[] found = directory.listFiles((FileFilter) filter);
474 
475         if (found != null) {
476             for (final File file : found) {
477                 if (file.isDirectory()) {
478                     if (includeSubDirectories) {
479                         files.add(file);
480                     }
481                     innerListFiles(files, file, filter, includeSubDirectories);
482                 } else {
483                     files.add(file);
484                 }
485             }
486         }
487     }
488 
489     /**
490      * Finds files within a given directory (and optionally its
491      * subdirectories). All files found are filtered by an IOFileFilter.
492      * <p>
493      * If your search should recurse into subdirectories you can pass in
494      * an IOFileFilter for directories. You don't need to bind a
495      * DirectoryFileFilter (via logical AND) to this filter. This method does
496      * that for you.
497      * <p>
498      * An example: If you want to search through all directories called
499      * "temp" you pass in <code>FileFilterUtils.NameFileFilter("temp")</code>
500      * <p>
501      * Another common usage of this method is find files in a directory
502      * tree but ignoring the directories generated CVS. You can simply pass
503      * in <code>FileFilterUtils.makeCVSAware(null)</code>.
504      *
505      * @param directory  the directory to search in
506      * @param fileFilter  filter to apply when finding files.
507      * @param dirFilter  optional filter to apply when finding subdirectories.
508      * If this parameter is {@code null}, subdirectories will not be included in the
509      * search. Use TrueFileFilter.INSTANCE to match all directories.
510      * @return an collection of java.io.File with the matching files
511      * @see org.apache.commons.io.filefilter.FileFilterUtils
512      * @see org.apache.commons.io.filefilter.NameFileFilter
513      */
514     public static Collection<File> listFiles(
515             final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
516         validateListFilesParameters(directory, fileFilter);
517 
518         final IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter);
519         final IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter);
520 
521         //Find files
522         final Collection<File> files = new java.util.LinkedList<File>();
523         innerListFiles(files, directory,
524             FileFilterUtils.or(effFileFilter, effDirFilter), false);
525         return files;
526     }
527 
528     /**
529      * Validates the given arguments.
530      * <ul>
531      * <li>Throws {@link IllegalArgumentException} if {@code directory} is not a directory</li>
532      * <li>Throws {@link NullPointerException} if {@code fileFilter} is null</li>
533      * </ul>
534      *
535      * @param directory The File to test
536      * @param fileFilter The IOFileFilter to test
537      */
538     private static void validateListFilesParameters(final File directory, final IOFileFilter fileFilter) {
539         if (!directory.isDirectory()) {
540             throw new IllegalArgumentException("Parameter 'directory' is not a directory: " + directory);
541         }
542         if (fileFilter == null) {
543             throw new NullPointerException("Parameter 'fileFilter' is null");
544         }
545     }
546 
547     /**
548      * Returns a filter that accepts files in addition to the {@link File} objects accepted by the given filter.
549      *
550      * @param fileFilter a base filter to add to
551      * @return a filter that accepts files
552      */
553     private static IOFileFilter setUpEffectiveFileFilter(final IOFileFilter fileFilter) {
554         return FileFilterUtils.and(fileFilter, FileFilterUtils.notFileFilter(DirectoryFileFilter.INSTANCE));
555     }
556 
557     /**
558      * Returns a filter that accepts directories in addition to the {@link File} objects accepted by the given filter.
559      *
560      * @param dirFilter a base filter to add to
561      * @return a filter that accepts directories
562      */
563     private static IOFileFilter setUpEffectiveDirFilter(final IOFileFilter dirFilter) {
564         return dirFilter == null ? FalseFileFilter.INSTANCE : FileFilterUtils.and(dirFilter,
565                 DirectoryFileFilter.INSTANCE);
566     }
567 
568     /**
569      * Finds files within a given directory (and optionally its
570      * subdirectories). All files found are filtered by an IOFileFilter.
571      * <p>
572      * The resulting collection includes the starting directory and
573      * any subdirectories that match the directory filter.
574      * <p>
575      * @see org.apache.commons.io.FileUtils#listFiles
576      *
577      * @param directory  the directory to search in
578      * @param fileFilter  filter to apply when finding files.
579      * @param dirFilter  optional filter to apply when finding subdirectories.
580      * If this parameter is {@code null}, subdirectories will not be included in the
581      * search. Use TrueFileFilter.INSTANCE to match all directories.
582      * @return an collection of java.io.File with the matching files
583      * @see org.apache.commons.io.filefilter.FileFilterUtils
584      * @see org.apache.commons.io.filefilter.NameFileFilter
585      * @since 2.2
586      */
587     public static Collection<File> listFilesAndDirs(
588             final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
589         validateListFilesParameters(directory, fileFilter);
590 
591         final IOFileFilter effFileFilter = setUpEffectiveFileFilter(fileFilter);
592         final IOFileFilter effDirFilter = setUpEffectiveDirFilter(dirFilter);
593 
594         //Find files
595         final Collection<File> files = new java.util.LinkedList<File>();
596         if (directory.isDirectory()) {
597             files.add(directory);
598         }
599         innerListFiles(files, directory,
600             FileFilterUtils.or(effFileFilter, effDirFilter), true);
601         return files;
602     }
603 
604     /**
605      * Allows iteration over the files in given directory (and optionally
606      * its subdirectories).
607      * <p>
608      * All files found are filtered by an IOFileFilter. This method is
609      * based on {@link #listFiles(File, IOFileFilter, IOFileFilter)},
610      * which supports Iterable ('foreach' loop).
611      * <p>
612      * @param directory  the directory to search in
613      * @param fileFilter  filter to apply when finding files.
614      * @param dirFilter  optional filter to apply when finding subdirectories.
615      * If this parameter is {@code null}, subdirectories will not be included in the
616      * search. Use TrueFileFilter.INSTANCE to match all directories.
617      * @return an iterator of java.io.File for the matching files
618      * @see org.apache.commons.io.filefilter.FileFilterUtils
619      * @see org.apache.commons.io.filefilter.NameFileFilter
620      * @since 1.2
621      */
622     public static Iterator<File> iterateFiles(
623             final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
624         return listFiles(directory, fileFilter, dirFilter).iterator();
625     }
626 
627     /**
628      * Allows iteration over the files in given directory (and optionally
629      * its subdirectories).
630      * <p>
631      * All files found are filtered by an IOFileFilter. This method is
632      * based on {@link #listFilesAndDirs(File, IOFileFilter, IOFileFilter)},
633      * which supports Iterable ('foreach' loop).
634      * <p>
635      * The resulting iterator includes the subdirectories themselves.
636      *
637      * @param directory  the directory to search in
638      * @param fileFilter  filter to apply when finding files.
639      * @param dirFilter  optional filter to apply when finding subdirectories.
640      * If this parameter is {@code null}, subdirectories will not be included in the
641      * search. Use TrueFileFilter.INSTANCE to match all directories.
642      * @return an iterator of java.io.File for the matching files
643      * @see org.apache.commons.io.filefilter.FileFilterUtils
644      * @see org.apache.commons.io.filefilter.NameFileFilter
645      * @since 2.2
646      */
647     public static Iterator<File> iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
648         return listFilesAndDirs(directory, fileFilter, dirFilter).iterator();
649     }
650 
651     //-----------------------------------------------------------------------
652     /**
653      * Converts an array of file extensions to suffixes for use
654      * with IOFileFilters.
655      *
656      * @param extensions  an array of extensions. Format: {"java", "xml"}
657      * @return an array of suffixes. Format: {".java", ".xml"}
658      */
659     private static String[] toSuffixes(final String[] extensions) {
660         final String[] suffixes = new String[extensions.length];
661         for (int i = 0; i < extensions.length; i++) {
662             suffixes[i] = "." + extensions[i];
663         }
664         return suffixes;
665     }
666 
667 
668     /**
669      * Finds files within a given directory (and optionally its subdirectories)
670      * which match an array of extensions.
671      *
672      * @param directory  the directory to search in
673      * @param extensions  an array of extensions, ex. {"java","xml"}. If this
674      * parameter is {@code null}, all files are returned.
675      * @param recursive  if true all subdirectories are searched as well
676      * @return an collection of java.io.File with the matching files
677      */
678     public static Collection<File> listFiles(
679             final File directory, final String[] extensions, final boolean recursive) {
680         IOFileFilter filter;
681         if (extensions == null) {
682             filter = TrueFileFilter.INSTANCE;
683         } else {
684             final String[] suffixes = toSuffixes(extensions);
685             filter = new SuffixFileFilter(suffixes);
686         }
687         return listFiles(directory, filter,
688             recursive ? TrueFileFilter.INSTANCE : FalseFileFilter.INSTANCE);
689     }
690 
691     /**
692      * Allows iteration over the files in a given directory (and optionally
693      * its subdirectories) which match an array of extensions. This method
694      * is based on {@link #listFiles(File, String[], boolean)},
695      * which supports Iterable ('foreach' loop).
696      *
697      * @param directory  the directory to search in
698      * @param extensions  an array of extensions, ex. {"java","xml"}. If this
699      * parameter is {@code null}, all files are returned.
700      * @param recursive  if true all subdirectories are searched as well
701      * @return an iterator of java.io.File with the matching files
702      * @since 1.2
703      */
704     public static Iterator<File> iterateFiles(
705             final File directory, final String[] extensions, final boolean recursive) {
706         return listFiles(directory, extensions, recursive).iterator();
707     }
708 
709     //-----------------------------------------------------------------------
710     /**
711      * Compares the contents of two files to determine if they are equal or not.
712      * <p>
713      * This method checks to see if the two files are different lengths
714      * or if they point to the same file, before resorting to byte-by-byte
715      * comparison of the contents.
716      * <p>
717      * Code origin: Avalon
718      *
719      * @param file1  the first file
720      * @param file2  the second file
721      * @return true if the content of the files are equal or they both don't
722      * exist, false otherwise
723      * @throws IOException in case of an I/O error
724      */
725     public static boolean contentEquals(final File file1, final File file2) throws IOException {
726         final boolean file1Exists = file1.exists();
727         if (file1Exists != file2.exists()) {
728             return false;
729         }
730 
731         if (!file1Exists) {
732             // two not existing files are equal
733             return true;
734         }
735 
736         if (file1.isDirectory() || file2.isDirectory()) {
737             // don't want to compare directory contents
738             throw new IOException("Can't compare directories, only files");
739         }
740 
741         if (file1.length() != file2.length()) {
742             // lengths differ, cannot be equal
743             return false;
744         }
745 
746         if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
747             // same file
748             return true;
749         }
750 
751         InputStream input1 = null;
752         InputStream input2 = null;
753         try {
754             input1 = new FileInputStream(file1);
755             input2 = new FileInputStream(file2);
756             return IOUtils.contentEquals(input1, input2);
757 
758         } finally {
759             IOUtils.closeQuietly(input1);
760             IOUtils.closeQuietly(input2);
761         }
762     }
763 
764     //-----------------------------------------------------------------------
765     /**
766      * Compares the contents of two files to determine if they are equal or not.
767      * <p>
768      * This method checks to see if the two files point to the same file,
769      * before resorting to line-by-line comparison of the contents.
770      * <p>
771      *
772      * @param file1  the first file
773      * @param file2  the second file
774      * @param charsetName the character encoding to be used.
775      *        May be null, in which case the platform default is used
776      * @return true if the content of the files are equal or neither exists,
777      *         false otherwise
778      * @throws IOException in case of an I/O error
779      * @since 2.2
780      * @see IOUtils#contentEqualsIgnoreEOL(Reader, Reader)
781      */
782     public static boolean contentEqualsIgnoreEOL(final File file1, final File file2, final String charsetName) throws IOException {
783         final boolean file1Exists = file1.exists();
784         if (file1Exists != file2.exists()) {
785             return false;
786         }
787 
788         if (!file1Exists) {
789             // two not existing files are equal
790             return true;
791         }
792 
793         if (file1.isDirectory() || file2.isDirectory()) {
794             // don't want to compare directory contents
795             throw new IOException("Can't compare directories, only files");
796         }
797 
798         if (file1.getCanonicalFile().equals(file2.getCanonicalFile())) {
799             // same file
800             return true;
801         }
802 
803         Reader input1 = null;
804         Reader input2 = null;
805         try {
806             if (charsetName == null) {
807                 // N.B. make explicit the use of the default charset
808                 input1 = new InputStreamReader(new FileInputStream(file1), Charset.defaultCharset());
809                 input2 = new InputStreamReader(new FileInputStream(file2), Charset.defaultCharset());
810             } else {
811                 input1 = new InputStreamReader(new FileInputStream(file1), charsetName);
812                 input2 = new InputStreamReader(new FileInputStream(file2), charsetName);
813             }
814             return IOUtils.contentEqualsIgnoreEOL(input1, input2);
815 
816         } finally {
817             IOUtils.closeQuietly(input1);
818             IOUtils.closeQuietly(input2);
819         }
820     }
821 
822     //-----------------------------------------------------------------------
823     /**
824      * Convert from a <code>URL</code> to a <code>File</code>.
825      * <p>
826      * From version 1.1 this method will decode the URL.
827      * Syntax such as <code>file:///my%20docs/file.txt</code> will be
828      * correctly decoded to <code>/my docs/file.txt</code>. Starting with version
829      * 1.5, this method uses UTF-8 to decode percent-encoded octets to characters.
830      * Additionally, malformed percent-encoded octets are handled leniently by
831      * passing them through literally.
832      *
833      * @param url  the file URL to convert, {@code null} returns {@code null}
834      * @return the equivalent <code>File</code> object, or {@code null}
835      *  if the URL's protocol is not <code>file</code>
836      */
837     public static File toFile(final URL url) {
838         if (url == null || !"file".equalsIgnoreCase(url.getProtocol())) {
839             return null;
840         } else {
841             String filename = url.getFile().replace('/', File.separatorChar);
842             filename = decodeUrl(filename);
843             return new File(filename);
844         }
845     }
846 
847     /**
848      * Decodes the specified URL as per RFC 3986, i.e. transforms
849      * percent-encoded octets to characters by decoding with the UTF-8 character
850      * set. This function is primarily intended for usage with
851      * {@link java.net.URL} which unfortunately does not enforce proper URLs. As
852      * such, this method will leniently accept invalid characters or malformed
853      * percent-encoded octets and simply pass them literally through to the
854      * result string. Except for rare edge cases, this will make unencoded URLs
855      * pass through unaltered.
856      *
857      * @param url  The URL to decode, may be {@code null}.
858      * @return The decoded URL or {@code null} if the input was
859      *         {@code null}.
860      */
861     static String decodeUrl(final String url) {
862         String decoded = url;
863         if (url != null && url.indexOf('%') >= 0) {
864             final int n = url.length();
865             final StringBuffer buffer = new StringBuffer();
866             final ByteBuffer bytes = ByteBuffer.allocate(n);
867             for (int i = 0; i < n;) {
868                 if (url.charAt(i) == '%') {
869                     try {
870                         do {
871                             final byte octet = (byte) Integer.parseInt(url.substring(i + 1, i + 3), 16);
872                             bytes.put(octet);
873                             i += 3;
874                         } while (i < n && url.charAt(i) == '%');
875                         continue;
876                     } catch (final RuntimeException e) {
877                         // malformed percent-encoded octet, fall through and
878                         // append characters literally
879                     } finally {
880                         if (bytes.position() > 0) {
881                             bytes.flip();
882                             buffer.append(Charsets.UTF_8.decode(bytes).toString());
883                             bytes.clear();
884                         }
885                     }
886                 }
887                 buffer.append(url.charAt(i++));
888             }
889             decoded = buffer.toString();
890         }
891         return decoded;
892     }
893 
894     /**
895      * Converts each of an array of <code>URL</code> to a <code>File</code>.
896      * <p>
897      * Returns an array of the same size as the input.
898      * If the input is {@code null}, an empty array is returned.
899      * If the input contains {@code null}, the output array contains {@code null} at the same
900      * index.
901      * <p>
902      * This method will decode the URL.
903      * Syntax such as <code>file:///my%20docs/file.txt</code> will be
904      * correctly decoded to <code>/my docs/file.txt</code>.
905      *
906      * @param urls  the file URLs to convert, {@code null} returns empty array
907      * @return a non-{@code null} array of Files matching the input, with a {@code null} item
908      *  if there was a {@code null} at that index in the input array
909      * @throws IllegalArgumentException if any file is not a URL file
910      * @throws IllegalArgumentException if any file is incorrectly encoded
911      * @since 1.1
912      */
913     public static File[] toFiles(final URL[] urls) {
914         if (urls == null || urls.length == 0) {
915             return EMPTY_FILE_ARRAY;
916         }
917         final File[] files = new File[urls.length];
918         for (int i = 0; i < urls.length; i++) {
919             final URL url = urls[i];
920             if (url != null) {
921                 if (url.getProtocol().equals("file") == false) {
922                     throw new IllegalArgumentException(
923                             "URL could not be converted to a File: " + url);
924                 }
925                 files[i] = toFile(url);
926             }
927         }
928         return files;
929     }
930 
931     /**
932      * Converts each of an array of <code>File</code> to a <code>URL</code>.
933      * <p>
934      * Returns an array of the same size as the input.
935      *
936      * @param files  the files to convert, must not be {@code null}
937      * @return an array of URLs matching the input
938      * @throws IOException if a file cannot be converted
939      * @throws NullPointerException if the parameter is null
940      */
941     public static URL[] toURLs(final File[] files) throws IOException {
942         final URL[] urls = new URL[files.length];
943 
944         for (int i = 0; i < urls.length; i++) {
945             urls[i] = files[i].toURI().toURL();
946         }
947 
948         return urls;
949     }
950 
951     //-----------------------------------------------------------------------
952     /**
953      * Copies a file to a directory preserving the file date.
954      * <p>
955      * This method copies the contents of the specified source file
956      * to a file of the same name in the specified destination directory.
957      * The destination directory is created if it does not exist.
958      * If the destination file exists, then this method will overwrite it.
959      * <p>
960      * <strong>Note:</strong> This method tries to preserve the file's last
961      * modified date/times using {@link File#setLastModified(long)}, however
962      * it is not guaranteed that the operation will succeed.
963      * If the modification operation fails, no indication is provided.
964      *
965      * @param srcFile  an existing file to copy, must not be {@code null}
966      * @param destDir  the directory to place the copy in, must not be {@code null}
967      *
968      * @throws NullPointerException if source or destination is null
969      * @throws IOException if source or destination is invalid
970      * @throws IOException if an IO error occurs during copying
971      * @see #copyFile(File, File, boolean)
972      */
973     public static void copyFileToDirectory(final File srcFile, final File destDir) throws IOException {
974         copyFileToDirectory(srcFile, destDir, true);
975     }
976 
977     /**
978      * Copies a file to a directory optionally preserving the file date.
979      * <p>
980      * This method copies the contents of the specified source file
981      * to a file of the same name in the specified destination directory.
982      * The destination directory is created if it does not exist.
983      * If the destination file exists, then this method will overwrite it.
984      * <p>
985      * <strong>Note:</strong> Setting <code>preserveFileDate</code> to
986      * {@code true} tries to preserve the file's last modified
987      * date/times using {@link File#setLastModified(long)}, however it is
988      * not guaranteed that the operation will succeed.
989      * If the modification operation fails, no indication is provided.
990      *
991      * @param srcFile  an existing file to copy, must not be {@code null}
992      * @param destDir  the directory to place the copy in, must not be {@code null}
993      * @param preserveFileDate  true if the file date of the copy
994      *  should be the same as the original
995      *
996      * @throws NullPointerException if source or destination is {@code null}
997      * @throws IOException if source or destination is invalid
998      * @throws IOException if an IO error occurs during copying
999      * @throws IOException if the output file length is not the same as the input file length after the copy completes
1000      * @see #copyFile(File, File, boolean)
1001      * @since 1.3
1002      */
1003     public static void copyFileToDirectory(final File srcFile, final File destDir, final boolean preserveFileDate) throws IOException {
1004         if (destDir == null) {
1005             throw new NullPointerException("Destination must not be null");
1006         }
1007         if (destDir.exists() && destDir.isDirectory() == false) {
1008             throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
1009         }
1010         final File destFile = new File(destDir, srcFile.getName());
1011         copyFile(srcFile, destFile, preserveFileDate);
1012     }
1013 
1014     /**
1015      * Copies a file to a new location preserving the file date.
1016      * <p>
1017      * This method copies the contents of the specified source file to the
1018      * specified destination file. The directory holding the destination file is
1019      * created if it does not exist. If the destination file exists, then this
1020      * method will overwrite it.
1021      * <p>
1022      * <strong>Note:</strong> This method tries to preserve the file's last
1023      * modified date/times using {@link File#setLastModified(long)}, however
1024      * it is not guaranteed that the operation will succeed.
1025      * If the modification operation fails, no indication is provided.
1026      *
1027      * @param srcFile  an existing file to copy, must not be {@code null}
1028      * @param destFile  the new file, must not be {@code null}
1029      *
1030      * @throws NullPointerException if source or destination is {@code null}
1031      * @throws IOException if source or destination is invalid
1032      * @throws IOException if an IO error occurs during copying
1033      * @throws IOException if the output file length is not the same as the input file length after the copy completes
1034      * @see #copyFileToDirectory(File, File)
1035      * @see #copyFile(File, File, boolean)
1036      */
1037     public static void copyFile(final File srcFile, final File destFile) throws IOException {
1038         copyFile(srcFile, destFile, true);
1039     }
1040 
1041     /**
1042      * Copies a file to a new location.
1043      * <p>
1044      * This method copies the contents of the specified source file
1045      * to the specified destination file.
1046      * The directory holding the destination file is created if it does not exist.
1047      * If the destination file exists, then this method will overwrite it.
1048      * <p>
1049      * <strong>Note:</strong> Setting <code>preserveFileDate</code> to
1050      * {@code true} tries to preserve the file's last modified
1051      * date/times using {@link File#setLastModified(long)}, however it is
1052      * not guaranteed that the operation will succeed.
1053      * If the modification operation fails, no indication is provided.
1054      *
1055      * @param srcFile  an existing file to copy, must not be {@code null}
1056      * @param destFile  the new file, must not be {@code null}
1057      * @param preserveFileDate  true if the file date of the copy
1058      *  should be the same as the original
1059      *
1060      * @throws NullPointerException if source or destination is {@code null}
1061      * @throws IOException if source or destination is invalid
1062      * @throws IOException if an IO error occurs during copying
1063      * @throws IOException if the output file length is not the same as the input file length after the copy completes
1064      * @see #copyFileToDirectory(File, File, boolean)
1065      * @see #doCopyFile(File, File, boolean)
1066      */
1067     public static void copyFile(final File srcFile, final File destFile,
1068             final boolean preserveFileDate) throws IOException {
1069         if (srcFile == null) {
1070             throw new NullPointerException("Source must not be null");
1071         }
1072         if (destFile == null) {
1073             throw new NullPointerException("Destination must not be null");
1074         }
1075         if (srcFile.exists() == false) {
1076             throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
1077         }
1078         if (srcFile.isDirectory()) {
1079             throw new IOException("Source '" + srcFile + "' exists but is a directory");
1080         }
1081         if (srcFile.getCanonicalPath().equals(destFile.getCanonicalPath())) {
1082             throw new IOException("Source '" + srcFile + "' and destination '" + destFile + "' are the same");
1083         }
1084         final File parentFile = destFile.getParentFile();
1085         if (parentFile != null) {
1086             if (!parentFile.mkdirs() && !parentFile.isDirectory()) {
1087                 throw new IOException("Destination '" + parentFile + "' directory cannot be created");
1088             }
1089         }
1090         if (destFile.exists() && destFile.canWrite() == false) {
1091             throw new IOException("Destination '" + destFile + "' exists but is read-only");
1092         }
1093         doCopyFile(srcFile, destFile, preserveFileDate);
1094     }
1095 
1096     /**
1097      * Copy bytes from a <code>File</code> to an <code>OutputStream</code>.
1098      * <p>
1099      * This method buffers the input internally, so there is no need to use a <code>BufferedInputStream</code>.
1100      * </p>
1101      *
1102      * @param input
1103      *            the <code>File</code> to read from
1104      * @param output
1105      *            the <code>OutputStream</code> to write to
1106      * @return the number of bytes copied
1107      * @throws NullPointerException
1108      *             if the input or output is null
1109      * @throws IOException
1110      *             if an I/O error occurs
1111      * @since 2.1
1112      */
1113     public static long copyFile(final File input, final OutputStream output) throws IOException {
1114         final FileInputStream fis = new FileInputStream(input);
1115         try {
1116             return IOUtils.copyLarge(fis, output);
1117         } finally {
1118             fis.close();
1119         }
1120     }
1121 
1122     /**
1123      * Internal copy file method.
1124      * This caches the original file length, and throws an IOException 
1125      * if the output file length is different from the current input file length.
1126      * So it may fail if the file changes size.
1127      * It may also fail with "IllegalArgumentException: Negative size" if the input file is truncated part way
1128      * through copying the data and the new file size is less than the current position.
1129      *
1130      * @param srcFile  the validated source file, must not be {@code null}
1131      * @param destFile  the validated destination file, must not be {@code null}
1132      * @param preserveFileDate  whether to preserve the file date
1133      * @throws IOException if an error occurs
1134      * @throws IOException if the output file length is not the same as the input file length after the copy completes
1135      * @throws IllegalArgumentException "Negative size" if the file is truncated so that the size is less than the position
1136      */
1137     private static void doCopyFile(final File srcFile, final File destFile, final boolean preserveFileDate) throws IOException {
1138         if (destFile.exists() && destFile.isDirectory()) {
1139             throw new IOException("Destination '" + destFile + "' exists but is a directory");
1140         }
1141 
1142         FileInputStream fis = null;
1143         FileOutputStream fos = null;
1144         FileChannel input = null;
1145         FileChannel output = null;
1146         try {
1147             fis = new FileInputStream(srcFile);
1148             fos = new FileOutputStream(destFile);
1149             input  = fis.getChannel();
1150             output = fos.getChannel();
1151             final long size = input.size(); // TODO See IO-386
1152             long pos = 0;
1153             long count = 0;
1154             while (pos < size) {
1155                 final long remain = size - pos;
1156                 count = remain > FILE_COPY_BUFFER_SIZE ? FILE_COPY_BUFFER_SIZE : remain;
1157                 final long bytesCopied = output.transferFrom(input, pos, count);
1158                 if (bytesCopied == 0) { // IO-385 - can happen if file is truncated after caching the size
1159                     break; // ensure we don't loop forever
1160                 }
1161                 pos += bytesCopied;
1162             }
1163         } finally {
1164             IOUtils.closeQuietly(output, fos, input, fis);
1165         }
1166 
1167         final long srcLen = srcFile.length(); // TODO See IO-386
1168         final long dstLen = destFile.length(); // TODO See IO-386
1169         if (srcLen != dstLen) {
1170             throw new IOException("Failed to copy full contents from '" +
1171                     srcFile + "' to '" + destFile + "' Expected length: " + srcLen +" Actual: " + dstLen);
1172         }
1173         if (preserveFileDate) {
1174             destFile.setLastModified(srcFile.lastModified());
1175         }
1176     }
1177 
1178     //-----------------------------------------------------------------------
1179     /**
1180      * Copies a directory to within another directory preserving the file dates.
1181      * <p>
1182      * This method copies the source directory and all its contents to a
1183      * directory of the same name in the specified destination directory.
1184      * <p>
1185      * The destination directory is created if it does not exist.
1186      * If the destination directory did exist, then this method merges
1187      * the source with the destination, with the source taking precedence.
1188      * <p>
1189      * <strong>Note:</strong> This method tries to preserve the files' last
1190      * modified date/times using {@link File#setLastModified(long)}, however
1191      * it is not guaranteed that those operations will succeed.
1192      * If the modification operation fails, no indication is provided.
1193      *
1194      * @param srcDir  an existing directory to copy, must not be {@code null}
1195      * @param destDir  the directory to place the copy in, must not be {@code null}
1196      *
1197      * @throws NullPointerException if source or destination is {@code null}
1198      * @throws IOException if source or destination is invalid
1199      * @throws IOException if an IO error occurs during copying
1200      * @since 1.2
1201      */
1202     public static void copyDirectoryToDirectory(final File srcDir, final File destDir) throws IOException {
1203         if (srcDir == null) {
1204             throw new NullPointerException("Source must not be null");
1205         }
1206         if (srcDir.exists() && srcDir.isDirectory() == false) {
1207             throw new IllegalArgumentException("Source '" + destDir + "' is not a directory");
1208         }
1209         if (destDir == null) {
1210             throw new NullPointerException("Destination must not be null");
1211         }
1212         if (destDir.exists() && destDir.isDirectory() == false) {
1213             throw new IllegalArgumentException("Destination '" + destDir + "' is not a directory");
1214         }
1215         copyDirectory(srcDir, new File(destDir, srcDir.getName()), true);
1216     }
1217 
1218     /**
1219      * Copies a whole directory to a new location preserving the file dates.
1220      * <p>
1221      * This method copies the specified directory and all its child
1222      * directories and files to the specified destination.
1223      * The destination is the new location and name of the directory.
1224      * <p>
1225      * The destination directory is created if it does not exist.
1226      * If the destination directory did exist, then this method merges
1227      * the source with the destination, with the source taking precedence.
1228      * <p>
1229      * <strong>Note:</strong> This method tries to preserve the files' last
1230      * modified date/times using {@link File#setLastModified(long)}, however
1231      * it is not guaranteed that those operations will succeed.
1232      * If the modification operation fails, no indication is provided.
1233      *
1234      * @param srcDir  an existing directory to copy, must not be {@code null}
1235      * @param destDir  the new directory, must not be {@code null}
1236      *
1237      * @throws NullPointerException if source or destination is {@code null}
1238      * @throws IOException if source or destination is invalid
1239      * @throws IOException if an IO error occurs during copying
1240      * @since 1.1
1241      */
1242     public static void copyDirectory(final File srcDir, final File destDir) throws IOException {
1243         copyDirectory(srcDir, destDir, true);
1244     }
1245 
1246     /**
1247      * Copies a whole directory to a new location.
1248      * <p>
1249      * This method copies the contents of the specified source directory
1250      * to within the specified destination directory.
1251      * <p>
1252      * The destination directory is created if it does not exist.
1253      * If the destination directory did exist, then this method merges
1254      * the source with the destination, with the source taking precedence.
1255      * <p>
1256      * <strong>Note:</strong> Setting <code>preserveFileDate</code> to
1257      * {@code true} tries to preserve the files' last modified
1258      * date/times using {@link File#setLastModified(long)}, however it is
1259      * not guaranteed that those operations will succeed.
1260      * If the modification operation fails, no indication is provided.
1261      *
1262      * @param srcDir  an existing directory to copy, must not be {@code null}
1263      * @param destDir  the new directory, must not be {@code null}
1264      * @param preserveFileDate  true if the file date of the copy
1265      *  should be the same as the original
1266      *
1267      * @throws NullPointerException if source or destination is {@code null}
1268      * @throws IOException if source or destination is invalid
1269      * @throws IOException if an IO error occurs during copying
1270      * @since 1.1
1271      */
1272     public static void copyDirectory(final File srcDir, final File destDir,
1273             final boolean preserveFileDate) throws IOException {
1274         copyDirectory(srcDir, destDir, null, preserveFileDate);
1275     }
1276 
1277     /**
1278      * Copies a filtered directory to a new location preserving the file dates.
1279      * <p>
1280      * This method copies the contents of the specified source directory
1281      * to within the specified destination directory.
1282      * <p>
1283      * The destination directory is created if it does not exist.
1284      * If the destination directory did exist, then this method merges
1285      * the source with the destination, with the source taking precedence.
1286      * <p>
1287      * <strong>Note:</strong> This method tries to preserve the files' last
1288      * modified date/times using {@link File#setLastModified(long)}, however
1289      * it is not guaranteed that those operations will succeed.
1290      * If the modification operation fails, no indication is provided.
1291      *
1292      * <h3>Example: Copy directories only</h3>
1293      *  <pre>
1294      *  // only copy the directory structure
1295      *  FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY);
1296      *  </pre>
1297      *
1298      * <h3>Example: Copy directories and txt files</h3>
1299      *  <pre>
1300      *  // Create a filter for ".txt" files
1301      *  IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
1302      *  IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
1303      *
1304      *  // Create a filter for either directories or ".txt" files
1305      *  FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
1306      *
1307      *  // Copy using the filter
1308      *  FileUtils.copyDirectory(srcDir, destDir, filter);
1309      *  </pre>
1310      *
1311      * @param srcDir  an existing directory to copy, must not be {@code null}
1312      * @param destDir  the new directory, must not be {@code null}
1313      * @param filter  the filter to apply, null means copy all directories and files
1314      *  should be the same as the original
1315      *
1316      * @throws NullPointerException if source or destination is {@code null}
1317      * @throws IOException if source or destination is invalid
1318      * @throws IOException if an IO error occurs during copying
1319      * @since 1.4
1320      */
1321     public static void copyDirectory(final File srcDir, final File destDir,
1322             final FileFilter filter) throws IOException {
1323         copyDirectory(srcDir, destDir, filter, true);
1324     }
1325 
1326     /**
1327      * Copies a filtered directory to a new location.
1328      * <p>
1329      * This method copies the contents of the specified source directory
1330      * to within the specified destination directory.
1331      * <p>
1332      * The destination directory is created if it does not exist.
1333      * If the destination directory did exist, then this method merges
1334      * the source with the destination, with the source taking precedence.
1335      * <p>
1336      * <strong>Note:</strong> Setting <code>preserveFileDate</code> to
1337      * {@code true} tries to preserve the files' last modified
1338      * date/times using {@link File#setLastModified(long)}, however it is
1339      * not guaranteed that those operations will succeed.
1340      * If the modification operation fails, no indication is provided.
1341      *
1342      * <h3>Example: Copy directories only</h3>
1343      *  <pre>
1344      *  // only copy the directory structure
1345      *  FileUtils.copyDirectory(srcDir, destDir, DirectoryFileFilter.DIRECTORY, false);
1346      *  </pre>
1347      *
1348      * <h3>Example: Copy directories and txt files</h3>
1349      *  <pre>
1350      *  // Create a filter for ".txt" files
1351      *  IOFileFilter txtSuffixFilter = FileFilterUtils.suffixFileFilter(".txt");
1352      *  IOFileFilter txtFiles = FileFilterUtils.andFileFilter(FileFileFilter.FILE, txtSuffixFilter);
1353      *
1354      *  // Create a filter for either directories or ".txt" files
1355      *  FileFilter filter = FileFilterUtils.orFileFilter(DirectoryFileFilter.DIRECTORY, txtFiles);
1356      *
1357      *  // Copy using the filter
1358      *  FileUtils.copyDirectory(srcDir, destDir, filter, false);
1359      *  </pre>
1360      *
1361      * @param srcDir  an existing directory to copy, must not be {@code null}
1362      * @param destDir  the new directory, must not be {@code null}
1363      * @param filter  the filter to apply, null means copy all directories and files
1364      * @param preserveFileDate  true if the file date of the copy
1365      *  should be the same as the original
1366      *
1367      * @throws NullPointerException if source or destination is {@code null}
1368      * @throws IOException if source or destination is invalid
1369      * @throws IOException if an IO error occurs during copying
1370      * @since 1.4
1371      */
1372     public static void copyDirectory(final File srcDir, final File destDir,
1373             final FileFilter filter, final boolean preserveFileDate) throws IOException {
1374         if (srcDir == null) {
1375             throw new NullPointerException("Source must not be null");
1376         }
1377         if (destDir == null) {
1378             throw new NullPointerException("Destination must not be null");
1379         }
1380         if (srcDir.exists() == false) {
1381             throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
1382         }
1383         if (srcDir.isDirectory() == false) {
1384             throw new IOException("Source '" + srcDir + "' exists but is not a directory");
1385         }
1386         if (srcDir.getCanonicalPath().equals(destDir.getCanonicalPath())) {
1387             throw new IOException("Source '" + srcDir + "' and destination '" + destDir + "' are the same");
1388         }
1389 
1390         // Cater for destination being directory within the source directory (see IO-141)
1391         List<String> exclusionList = null;
1392         if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath())) {
1393             final File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
1394             if (srcFiles != null && srcFiles.length > 0) {
1395                 exclusionList = new ArrayList<String>(srcFiles.length);
1396                 for (final File srcFile : srcFiles) {
1397                     final File copiedFile = new File(destDir, srcFile.getName());
1398                     exclusionList.add(copiedFile.getCanonicalPath());
1399                 }
1400             }
1401         }
1402         doCopyDirectory(srcDir, destDir, filter, preserveFileDate, exclusionList);
1403     }
1404 
1405     /**
1406      * Internal copy directory method.
1407      *
1408      * @param srcDir  the validated source directory, must not be {@code null}
1409      * @param destDir  the validated destination directory, must not be {@code null}
1410      * @param filter  the filter to apply, null means copy all directories and files
1411      * @param preserveFileDate  whether to preserve the file date
1412      * @param exclusionList  List of files and directories to exclude from the copy, may be null
1413      * @throws IOException if an error occurs
1414      * @since 1.1
1415      */
1416     private static void doCopyDirectory(final File srcDir, final File destDir, final FileFilter filter,
1417             final boolean preserveFileDate, final List<String> exclusionList) throws IOException {
1418         // recurse
1419         final File[] srcFiles = filter == null ? srcDir.listFiles() : srcDir.listFiles(filter);
1420         if (srcFiles == null) {  // null if abstract pathname does not denote a directory, or if an I/O error occurs
1421             throw new IOException("Failed to list contents of " + srcDir);
1422         }
1423         if (destDir.exists()) {
1424             if (destDir.isDirectory() == false) {
1425                 throw new IOException("Destination '" + destDir + "' exists but is not a directory");
1426             }
1427         } else {
1428             if (!destDir.mkdirs() && !destDir.isDirectory()) {
1429                 throw new IOException("Destination '" + destDir + "' directory cannot be created");
1430             }
1431         }
1432         if (destDir.canWrite() == false) {
1433             throw new IOException("Destination '" + destDir + "' cannot be written to");
1434         }
1435         for (final File srcFile : srcFiles) {
1436             final File dstFile = new File(destDir, srcFile.getName());
1437             if (exclusionList == null || !exclusionList.contains(srcFile.getCanonicalPath())) {
1438                 if (srcFile.isDirectory()) {
1439                     doCopyDirectory(srcFile, dstFile, filter, preserveFileDate, exclusionList);
1440                 } else {
1441                     doCopyFile(srcFile, dstFile, preserveFileDate);
1442                 }
1443             }
1444         }
1445 
1446         // Do this last, as the above has probably affected directory metadata
1447         if (preserveFileDate) {
1448             destDir.setLastModified(srcDir.lastModified());
1449         }
1450     }
1451 
1452     //-----------------------------------------------------------------------
1453     /**
1454      * Copies bytes from the URL <code>source</code> to a file
1455      * <code>destination</code>. The directories up to <code>destination</code>
1456      * will be created if they don't already exist. <code>destination</code>
1457      * will be overwritten if it already exists.
1458      * <p>
1459      * Warning: this method does not set a connection or read timeout and thus
1460      * might block forever. Use {@link #copyURLToFile(URL, File, int, int)}
1461      * with reasonable timeouts to prevent this.
1462      *
1463      * @param source  the <code>URL</code> to copy bytes from, must not be {@code null}
1464      * @param destination  the non-directory <code>File</code> to write bytes to
1465      *  (possibly overwriting), must not be {@code null}
1466      * @throws IOException if <code>source</code> URL cannot be opened
1467      * @throws IOException if <code>destination</code> is a directory
1468      * @throws IOException if <code>destination</code> cannot be written
1469      * @throws IOException if <code>destination</code> needs creating but can't be
1470      * @throws IOException if an IO error occurs during copying
1471      */
1472     public static void copyURLToFile(final URL source, final File destination) throws IOException {
1473         copyInputStreamToFile(source.openStream(), destination);
1474     }
1475 
1476     /**
1477      * Copies bytes from the URL <code>source</code> to a file
1478      * <code>destination</code>. The directories up to <code>destination</code>
1479      * will be created if they don't already exist. <code>destination</code>
1480      * will be overwritten if it already exists.
1481      *
1482      * @param source  the <code>URL</code> to copy bytes from, must not be {@code null}
1483      * @param destination  the non-directory <code>File</code> to write bytes to
1484      *  (possibly overwriting), must not be {@code null}
1485      * @param connectionTimeout the number of milliseconds until this method
1486      *  will timeout if no connection could be established to the <code>source</code>
1487      * @param readTimeout the number of milliseconds until this method will
1488      *  timeout if no data could be read from the <code>source</code>
1489      * @throws IOException if <code>source</code> URL cannot be opened
1490      * @throws IOException if <code>destination</code> is a directory
1491      * @throws IOException if <code>destination</code> cannot be written
1492      * @throws IOException if <code>destination</code> needs creating but can't be
1493      * @throws IOException if an IO error occurs during copying
1494      * @since 2.0
1495      */
1496     public static void copyURLToFile(final URL source, final File destination,
1497             final int connectionTimeout, final int readTimeout) throws IOException {
1498         final URLConnection connection = source.openConnection();
1499         connection.setConnectTimeout(connectionTimeout);
1500         connection.setReadTimeout(readTimeout);
1501         copyInputStreamToFile(connection.getInputStream(), destination);
1502     }
1503 
1504     /**
1505      * Copies bytes from an {@link InputStream} <code>source</code> to a file
1506      * <code>destination</code>. The directories up to <code>destination</code>
1507      * will be created if they don't already exist. <code>destination</code>
1508      * will be overwritten if it already exists.
1509      * The {@code source} stream is closed.
1510      *
1511      * @param source  the <code>InputStream</code> to copy bytes from, must not be {@code null}, will be closed
1512      * @param destination  the non-directory <code>File</code> to write bytes to
1513      *  (possibly overwriting), must not be {@code null}
1514      * @throws IOException if <code>destination</code> is a directory
1515      * @throws IOException if <code>destination</code> cannot be written
1516      * @throws IOException if <code>destination</code> needs creating but can't be
1517      * @throws IOException if an IO error occurs during copying
1518      * @since 2.0
1519      */
1520     public static void copyInputStreamToFile(final InputStream source, final File destination) throws IOException {
1521         try {
1522             copyToFile(source, destination);
1523         } finally {
1524             IOUtils.closeQuietly(source);
1525         }
1526     }
1527 
1528     /**
1529      * Copies bytes from an {@link InputStream} <code>source</code> to a file
1530      * <code>destination</code>. The directories up to <code>destination</code>
1531      * will be created if they don't already exist. <code>destination</code>
1532      * will be overwritten if it already exists.
1533      * The {@code source} stream is left open, e.g. for use with {@link java.util.zip.ZipInputStream ZipInputStream}.
1534      *
1535      * @param source  the <code>InputStream</code> to copy bytes from, must not be {@code null}
1536      * @param destination  the non-directory <code>File</code> to write bytes to
1537      *  (possibly overwriting), must not be {@code null}
1538      * @throws IOException if <code>destination</code> is a directory
1539      * @throws IOException if <code>destination</code> cannot be written
1540      * @throws IOException if <code>destination</code> needs creating but can't be
1541      * @throws IOException if an IO error occurs during copying
1542      * @since 2.5
1543      */
1544     public static void copyToFile(final InputStream source, final File destination) throws IOException {
1545         final FileOutputStream output = openOutputStream(destination);
1546         try {
1547             IOUtils.copy(source, output);
1548             output.close(); // don't swallow close Exception if copy completes normally
1549         } finally {
1550             IOUtils.closeQuietly(output);
1551         }
1552     }
1553 
1554     //-----------------------------------------------------------------------
1555     /**
1556      * Deletes a directory recursively.
1557      *
1558      * @param directory  directory to delete
1559      * @throws IOException in case deletion is unsuccessful
1560      */
1561     public static void deleteDirectory(final File directory) throws IOException {
1562         if (!directory.exists()) {
1563             return;
1564         }
1565 
1566         if (!isSymlink(directory)) {
1567             cleanDirectory(directory);
1568         }
1569 
1570         if (!directory.delete()) {
1571             final String message =
1572                 "Unable to delete directory " + directory + ".";
1573             throw new IOException(message);
1574         }
1575     }
1576 
1577     /**
1578      * Deletes a file, never throwing an exception. If file is a directory, delete it and all sub-directories.
1579      * <p>
1580      * The difference between File.delete() and this method are:
1581      * <ul>
1582      * <li>A directory to be deleted does not have to be empty.</li>
1583      * <li>No exceptions are thrown when a file or directory cannot be deleted.</li>
1584      * </ul>
1585      *
1586      * @param file  file or directory to delete, can be {@code null}
1587      * @return {@code true} if the file or directory was deleted, otherwise
1588      * {@code false}
1589      *
1590      * @since 1.4
1591      */
1592     public static boolean deleteQuietly(final File file) {
1593         if (file == null) {
1594             return false;
1595         }
1596         try {
1597             if (file.isDirectory()) {
1598                 cleanDirectory(file);
1599             }
1600         } catch (final Exception ignored) {
1601         }
1602 
1603         try {
1604             return file.delete();
1605         } catch (final Exception ignored) {
1606             return false;
1607         }
1608     }
1609 
1610     /**
1611      * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory).
1612      * <p>
1613      * Files are normalized before comparison.
1614      * </p>
1615      *
1616      * Edge cases:
1617      * <ul>
1618      * <li>A {@code directory} must not be null: if null, throw IllegalArgumentException</li>
1619      * <li>A {@code directory} must be a directory: if not a directory, throw IllegalArgumentException</li>
1620      * <li>A directory does not contain itself: return false</li>
1621      * <li>A null child file is not contained in any parent: return false</li>
1622      * </ul>
1623      *
1624      * @param directory
1625      *            the file to consider as the parent.
1626      * @param child
1627      *            the file to consider as the child.
1628      * @return true is the candidate leaf is under by the specified composite. False otherwise.
1629      * @throws IOException
1630      *             if an IO error occurs while checking the files.
1631      * @since 2.2
1632      * @see FilenameUtils#directoryContains(String, String)
1633      */
1634     public static boolean directoryContains(final File directory, final File child) throws IOException {
1635 
1636         // Fail fast against NullPointerException
1637         if (directory == null) {
1638             throw new IllegalArgumentException("Directory must not be null");
1639         }
1640 
1641         if (!directory.isDirectory()) {
1642             throw new IllegalArgumentException("Not a directory: " + directory);
1643         }
1644 
1645         if (child == null) {
1646             return false;
1647         }
1648 
1649         if (!directory.exists() || !child.exists()) {
1650             return false;
1651         }
1652 
1653         // Canonicalize paths (normalizes relative paths)
1654         final String canonicalParent = directory.getCanonicalPath();
1655         final String canonicalChild = child.getCanonicalPath();
1656 
1657         return FilenameUtils.directoryContains(canonicalParent, canonicalChild);
1658     }
1659 
1660     /**
1661      * Cleans a directory without deleting it.
1662      *
1663      * @param directory directory to clean
1664      * @throws IOException in case cleaning is unsuccessful
1665      */
1666     public static void cleanDirectory(final File directory) throws IOException {
1667         if (!directory.exists()) {
1668             final String message = directory + " does not exist";
1669             throw new IllegalArgumentException(message);
1670         }
1671 
1672         if (!directory.isDirectory()) {
1673             final String message = directory + " is not a directory";
1674             throw new IllegalArgumentException(message);
1675         }
1676 
1677         final File[] files = directory.listFiles();
1678         if (files == null) {  // null if security restricted
1679             throw new IOException("Failed to list contents of " + directory);
1680         }
1681 
1682         IOException exception = null;
1683         for (final File file : files) {
1684             try {
1685                 forceDelete(file);
1686             } catch (final IOException ioe) {
1687                 exception = ioe;
1688             }
1689         }
1690 
1691         if (null != exception) {
1692             throw exception;
1693         }
1694     }
1695 
1696     //-----------------------------------------------------------------------
1697     /**
1698      * Waits for NFS to propagate a file creation, imposing a timeout.
1699      * <p>
1700      * This method repeatedly tests {@link File#exists()} until it returns
1701      * true up to the maximum time specified in seconds.
1702      *
1703      * @param file  the file to check, must not be {@code null}
1704      * @param seconds  the maximum time in seconds to wait
1705      * @return true if file exists
1706      * @throws NullPointerException if the file is {@code null}
1707      */
1708     public static boolean waitFor(final File file, final int seconds) {
1709         int timeout = 0;
1710         int tick = 0;
1711         while (!file.exists()) {
1712             if (tick++ >= 10) {
1713                 tick = 0;
1714                 if (timeout++ > seconds) {
1715                     return false;
1716                 }
1717             }
1718             try {
1719                 Thread.sleep(100);
1720             } catch (final InterruptedException ignore) {
1721                 // ignore exception
1722             } catch (final Exception ex) {
1723                 break;
1724             }
1725         }
1726         return true;
1727     }
1728 
1729     //-----------------------------------------------------------------------
1730     /**
1731      * Reads the contents of a file into a String.
1732      * The file is always closed.
1733      *
1734      * @param file  the file to read, must not be {@code null}
1735      * @param encoding  the encoding to use, {@code null} means platform default
1736      * @return the file contents, never {@code null}
1737      * @throws IOException in case of an I/O error
1738      * @since 2.3
1739      */
1740     public static String readFileToString(final File file, final Charset encoding) throws IOException {
1741         InputStream in = null;
1742         try {
1743             in = openInputStream(file);
1744             return IOUtils.toString(in, Charsets.toCharset(encoding));
1745         } finally {
1746             IOUtils.closeQuietly(in);
1747         }
1748     }
1749 
1750     /**
1751      * Reads the contents of a file into a String. The file is always closed.
1752      *
1753      * @param file
1754      *            the file to read, must not be {@code null}
1755      * @param encoding
1756      *            the encoding to use, {@code null} means platform default
1757      * @return the file contents, never {@code null}
1758      * @throws IOException
1759      *             in case of an I/O error
1760      * @throws UnsupportedCharsetException
1761      *             thrown instead of {@link UnsupportedEncodingException} in version 2.2 if the encoding is not
1762      *             supported.
1763      * @since 2.3
1764      */
1765     public static String readFileToString(final File file, final String encoding) throws IOException {
1766         return readFileToString(file, Charsets.toCharset(encoding));
1767     }
1768 
1769 
1770     /**
1771      * Reads the contents of a file into a String using the default encoding for the VM.
1772      * The file is always closed.
1773      *
1774      * @param file  the file to read, must not be {@code null}
1775      * @return the file contents, never {@code null}
1776      * @throws IOException in case of an I/O error
1777      * @since 1.3.1
1778      * @deprecated 2.5 use {@link #readFileToString(File, Charset)} instead
1779      */
1780     @Deprecated
1781     public static String readFileToString(final File file) throws IOException {
1782         return readFileToString(file, Charset.defaultCharset());
1783     }
1784 
1785     /**
1786      * Reads the contents of a file into a byte array.
1787      * The file is always closed.
1788      *
1789      * @param file  the file to read, must not be {@code null}
1790      * @return the file contents, never {@code null}
1791      * @throws IOException in case of an I/O error
1792      * @since 1.1
1793      */
1794     public static byte[] readFileToByteArray(final File file) throws IOException {
1795         InputStream in = null;
1796         try {
1797             in = openInputStream(file);
1798             return IOUtils.toByteArray(in, file.length());
1799         } finally {
1800             IOUtils.closeQuietly(in);
1801         }
1802     }
1803 
1804     /**
1805      * Reads the contents of a file line by line to a List of Strings.
1806      * The file is always closed.
1807      *
1808      * @param file  the file to read, must not be {@code null}
1809      * @param encoding  the encoding to use, {@code null} means platform default
1810      * @return the list of Strings representing each line in the file, never {@code null}
1811      * @throws IOException in case of an I/O error
1812      * @since 2.3
1813      */
1814     public static List<String> readLines(final File file, final Charset encoding) throws IOException {
1815         InputStream in = null;
1816         try {
1817             in = openInputStream(file);
1818             return IOUtils.readLines(in, Charsets.toCharset(encoding));
1819         } finally {
1820             IOUtils.closeQuietly(in);
1821         }
1822     }
1823 
1824     /**
1825      * Reads the contents of a file line by line to a List of Strings. The file is always closed.
1826      *
1827      * @param file
1828      *            the file to read, must not be {@code null}
1829      * @param encoding
1830      *            the encoding to use, {@code null} means platform default
1831      * @return the list of Strings representing each line in the file, never {@code null}
1832      * @throws IOException
1833      *             in case of an I/O error
1834      * @throws UnsupportedCharsetException
1835      *             thrown instead of {@link UnsupportedEncodingException} in version 2.2 if the encoding is not
1836      *             supported.
1837      * @since 1.1
1838      */
1839     public static List<String> readLines(final File file, final String encoding) throws IOException {
1840         return readLines(file, Charsets.toCharset(encoding));
1841     }
1842 
1843     /**
1844      * Reads the contents of a file line by line to a List of Strings using the default encoding for the VM.
1845      * The file is always closed.
1846      *
1847      * @param file  the file to read, must not be {@code null}
1848      * @return the list of Strings representing each line in the file, never {@code null}
1849      * @throws IOException in case of an I/O error
1850      * @since 1.3
1851      * @deprecated 2.5 use {@link #readLines(File, Charset)} instead
1852      */
1853     @Deprecated
1854     public static List<String> readLines(final File file) throws IOException {
1855         return readLines(file, Charset.defaultCharset());
1856     }
1857 
1858     /**
1859      * Returns an Iterator for the lines in a <code>File</code>.
1860      * <p>
1861      * This method opens an <code>InputStream</code> for the file.
1862      * When you have finished with the iterator you should close the stream
1863      * to free internal resources. This can be done by calling the
1864      * {@link LineIterator#close()} or
1865      * {@link LineIterator#closeQuietly(LineIterator)} method.
1866      * <p>
1867      * The recommended usage pattern is:
1868      * <pre>
1869      * LineIterator it = FileUtils.lineIterator(file, "UTF-8");
1870      * try {
1871      *   while (it.hasNext()) {
1872      *     String line = it.nextLine();
1873      *     /// do something with line
1874      *   }
1875      * } finally {
1876      *   LineIterator.closeQuietly(iterator);
1877      * }
1878      * </pre>
1879      * <p>
1880      * If an exception occurs during the creation of the iterator, the
1881      * underlying stream is closed.
1882      *
1883      * @param file  the file to open for input, must not be {@code null}
1884      * @param encoding  the encoding to use, {@code null} means platform default
1885      * @return an Iterator of the lines in the file, never {@code null}
1886      * @throws IOException in case of an I/O error (file closed)
1887      * @since 1.2
1888      */
1889     public static LineIterator lineIterator(final File file, final String encoding) throws IOException {
1890         InputStream in = null;
1891         try {
1892             in = openInputStream(file);
1893             return IOUtils.lineIterator(in, encoding);
1894         } catch (final IOException ex) {
1895             IOUtils.closeQuietly(in);
1896             throw ex;
1897         } catch (final RuntimeException ex) {
1898             IOUtils.closeQuietly(in);
1899             throw ex;
1900         }
1901     }
1902 
1903     /**
1904      * Returns an Iterator for the lines in a <code>File</code> using the default encoding for the VM.
1905      *
1906      * @param file  the file to open for input, must not be {@code null}
1907      * @return an Iterator of the lines in the file, never {@code null}
1908      * @throws IOException in case of an I/O error (file closed)
1909      * @since 1.3
1910      * @see #lineIterator(File, String)
1911      */
1912     public static LineIterator lineIterator(final File file) throws IOException {
1913         return lineIterator(file, null);
1914     }
1915 
1916     //-----------------------------------------------------------------------
1917     /**
1918      * Writes a String to a file creating the file if it does not exist.
1919      *
1920      * NOTE: As from v1.3, the parent directories of the file will be created
1921      * if they do not exist.
1922      *
1923      * @param file  the file to write
1924      * @param data  the content to write to the file
1925      * @param encoding  the encoding to use, {@code null} means platform default
1926      * @throws IOException in case of an I/O error
1927      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
1928      * @since 2.4
1929      */
1930     public static void writeStringToFile(final File file, final String data, final Charset encoding) throws IOException {
1931         writeStringToFile(file, data, encoding, false);
1932     }
1933 
1934     /**
1935      * Writes a String to a file creating the file if it does not exist.
1936      *
1937      * NOTE: As from v1.3, the parent directories of the file will be created
1938      * if they do not exist.
1939      *
1940      * @param file  the file to write
1941      * @param data  the content to write to the file
1942      * @param encoding  the encoding to use, {@code null} means platform default
1943      * @throws IOException in case of an I/O error
1944      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
1945      */
1946     public static void writeStringToFile(final File file, final String data, final String encoding) throws IOException {
1947         writeStringToFile(file, data, encoding, false);
1948     }
1949 
1950     /**
1951      * Writes a String to a file creating the file if it does not exist.
1952      *
1953      * @param file  the file to write
1954      * @param data  the content to write to the file
1955      * @param encoding  the encoding to use, {@code null} means platform default
1956      * @param append if {@code true}, then the String will be added to the
1957      * end of the file rather than overwriting
1958      * @throws IOException in case of an I/O error
1959      * @since 2.3
1960      */
1961     public static void writeStringToFile(final File file, final String data, final Charset encoding, final boolean append) throws IOException {
1962         OutputStream out = null;
1963         try {
1964             out = openOutputStream(file, append);
1965             IOUtils.write(data, out, encoding);
1966             out.close(); // don't swallow close Exception if copy completes normally
1967         } finally {
1968             IOUtils.closeQuietly(out);
1969         }
1970     }
1971 
1972     /**
1973      * Writes a String to a file creating the file if it does not exist.
1974      *
1975      * @param file  the file to write
1976      * @param data  the content to write to the file
1977      * @param encoding  the encoding to use, {@code null} means platform default
1978      * @param append if {@code true}, then the String will be added to the
1979      * end of the file rather than overwriting
1980      * @throws IOException in case of an I/O error
1981      * @throws UnsupportedCharsetException
1982      *             thrown instead of {@link UnsupportedEncodingException} in version 2.2 if the encoding is not
1983      *             supported by the VM
1984      * @since 2.1
1985      */
1986     public static void writeStringToFile(final File file, final String data, final String encoding, final boolean append) throws IOException {
1987         writeStringToFile(file, data, Charsets.toCharset(encoding), append);
1988     }
1989 
1990     /**
1991      * Writes a String to a file creating the file if it does not exist using the default encoding for the VM.
1992      *
1993      * @param file  the file to write
1994      * @param data  the content to write to the file
1995      * @throws IOException in case of an I/O error
1996      * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset)} instead
1997      */
1998     @Deprecated
1999     public static void writeStringToFile(final File file, final String data) throws IOException {
2000         writeStringToFile(file, data, Charset.defaultCharset(), false);
2001     }
2002 
2003     /**
2004      * Writes a String to a file creating the file if it does not exist using the default encoding for the VM.
2005      *
2006      * @param file  the file to write
2007      * @param data  the content to write to the file
2008      * @param append if {@code true}, then the String will be added to the
2009      * end of the file rather than overwriting
2010      * @throws IOException in case of an I/O error
2011      * @since 2.1
2012      * @deprecated 2.5 use {@link #writeStringToFile(File, String, Charset, boolean)} instead
2013      */
2014     @Deprecated
2015     public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException {
2016         writeStringToFile(file, data, Charset.defaultCharset(), append);
2017     }
2018 
2019     /**
2020      * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM.
2021      *
2022      * @param file  the file to write
2023      * @param data  the content to write to the file
2024      * @throws IOException in case of an I/O error
2025      * @since 2.0
2026      * @deprecated 2.5 use {@link #write(File, CharSequence, Charset)} instead
2027      */
2028     @Deprecated
2029     public static void write(final File file, final CharSequence data) throws IOException {
2030         write(file, data, Charset.defaultCharset(), false);
2031     }
2032 
2033     /**
2034      * Writes a CharSequence to a file creating the file if it does not exist using the default encoding for the VM.
2035      *
2036      * @param file  the file to write
2037      * @param data  the content to write to the file
2038      * @param append if {@code true}, then the data will be added to the
2039      * end of the file rather than overwriting
2040      * @throws IOException in case of an I/O error
2041      * @since 2.1
2042      * @deprecated 2.5 use {@link #write(File, CharSequence, Charset, boolean)} instead
2043      */
2044     @Deprecated
2045     public static void write(final File file, final CharSequence data, final boolean append) throws IOException {
2046         write(file, data, Charset.defaultCharset(), append);
2047     }
2048 
2049     /**
2050      * Writes a CharSequence to a file creating the file if it does not exist.
2051      *
2052      * @param file  the file to write
2053      * @param data  the content to write to the file
2054      * @param encoding  the encoding to use, {@code null} means platform default
2055      * @throws IOException in case of an I/O error
2056      * @since 2.3
2057      */
2058     public static void write(final File file, final CharSequence data, final Charset encoding) throws IOException {
2059         write(file, data, encoding, false);
2060     }
2061 
2062     /**
2063      * Writes a CharSequence to a file creating the file if it does not exist.
2064      *
2065      * @param file  the file to write
2066      * @param data  the content to write to the file
2067      * @param encoding  the encoding to use, {@code null} means platform default
2068      * @throws IOException in case of an I/O error
2069      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
2070      * @since 2.0
2071      */
2072     public static void write(final File file, final CharSequence data, final String encoding) throws IOException {
2073         write(file, data, encoding, false);
2074     }
2075 
2076     /**
2077      * Writes a CharSequence to a file creating the file if it does not exist.
2078      *
2079      * @param file  the file to write
2080      * @param data  the content to write to the file
2081      * @param encoding  the encoding to use, {@code null} means platform default
2082      * @param append if {@code true}, then the data will be added to the
2083      * end of the file rather than overwriting
2084      * @throws IOException in case of an I/O error
2085      * @since 2.3
2086      */
2087     public static void write(final File file, final CharSequence data, final Charset encoding, final boolean append) throws IOException {
2088         final String str = data == null ? null : data.toString();
2089         writeStringToFile(file, str, encoding, append);
2090     }
2091 
2092     /**
2093      * Writes a CharSequence to a file creating the file if it does not exist.
2094      *
2095      * @param file  the file to write
2096      * @param data  the content to write to the file
2097      * @param encoding  the encoding to use, {@code null} means platform default
2098      * @param append if {@code true}, then the data will be added to the
2099      * end of the file rather than overwriting
2100      * @throws IOException in case of an I/O error
2101      * @throws UnsupportedCharsetException
2102      *             thrown instead of {@link UnsupportedEncodingException} in version 2.2 if the encoding is not
2103      *             supported by the VM
2104      * @since 2.1
2105      */
2106     public static void write(final File file, final CharSequence data, final String encoding, final boolean append) throws IOException {
2107         write(file, data, Charsets.toCharset(encoding), append);
2108     }
2109 
2110     /**
2111      * Writes a byte array to a file creating the file if it does not exist.
2112      * <p>
2113      * NOTE: As from v1.3, the parent directories of the file will be created
2114      * if they do not exist.
2115      *
2116      * @param file  the file to write to
2117      * @param data  the content to write to the file
2118      * @throws IOException in case of an I/O error
2119      * @since 1.1
2120      */
2121     public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException {
2122         writeByteArrayToFile(file, data, false);
2123     }
2124 
2125     /**
2126      * Writes a byte array to a file creating the file if it does not exist.
2127      *
2128      * @param file  the file to write to
2129      * @param data  the content to write to the file
2130      * @param append if {@code true}, then bytes will be added to the
2131      * end of the file rather than overwriting
2132      * @throws IOException in case of an I/O error
2133      * @since 2.1
2134      */
2135     public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException {
2136         writeByteArrayToFile(file, data, 0, data.length, append);
2137     }
2138 
2139     /**
2140      * Writes {@code len} bytes from the specified byte array starting
2141      * at offset {@code off} to a file, creating the file if it does
2142      * not exist.
2143      *
2144      * @param file  the file to write to
2145      * @param data  the content to write to the file
2146      * @param off   the start offset in the data
2147      * @param len   the number of bytes to write
2148      * @throws IOException in case of an I/O error
2149      * @since 2.5
2150      */
2151     public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException {
2152         writeByteArrayToFile(file, data, off, len, false);
2153     }
2154 
2155     /**
2156      * Writes {@code len} bytes from the specified byte array starting
2157      * at offset {@code off} to a file, creating the file if it does
2158      * not exist.
2159      *
2160      * @param file  the file to write to
2161      * @param data  the content to write to the file
2162      * @param off   the start offset in the data
2163      * @param len   the number of bytes to write
2164      * @param append if {@code true}, then bytes will be added to the
2165      * end of the file rather than overwriting
2166      * @throws IOException in case of an I/O error
2167      * @since 2.5
2168      */
2169     public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException {
2170         OutputStream out = null;
2171         try {
2172             out = openOutputStream(file, append);
2173             out.write(data, off, len);
2174             out.close(); // don't swallow close Exception if copy completes normally
2175         } finally {
2176             IOUtils.closeQuietly(out);
2177         }
2178     }
2179 
2180     /**
2181      * Writes the <code>toString()</code> value of each item in a collection to
2182      * the specified <code>File</code> line by line.
2183      * The specified character encoding and the default line ending will be used.
2184      * <p>
2185      * NOTE: As from v1.3, the parent directories of the file will be created
2186      * if they do not exist.
2187      *
2188      * @param file  the file to write to
2189      * @param encoding  the encoding to use, {@code null} means platform default
2190      * @param lines  the lines to write, {@code null} entries produce blank lines
2191      * @throws IOException in case of an I/O error
2192      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
2193      * @since 1.1
2194      */
2195     public static void writeLines(final File file, final String encoding, final Collection<?> lines) throws IOException {
2196         writeLines(file, encoding, lines, null, false);
2197     }
2198 
2199     /**
2200      * Writes the <code>toString()</code> value of each item in a collection to
2201      * the specified <code>File</code> line by line, optionally appending.
2202      * The specified character encoding and the default line ending will be used.
2203      *
2204      * @param file  the file to write to
2205      * @param encoding  the encoding to use, {@code null} means platform default
2206      * @param lines  the lines to write, {@code null} entries produce blank lines
2207      * @param append if {@code true}, then the lines will be added to the
2208      * end of the file rather than overwriting
2209      * @throws IOException in case of an I/O error
2210      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
2211      * @since 2.1
2212      */
2213     public static void writeLines(final File file, final String encoding, final Collection<?> lines, final boolean append) throws IOException {
2214         writeLines(file, encoding, lines, null, append);
2215     }
2216 
2217     /**
2218      * Writes the <code>toString()</code> value of each item in a collection to
2219      * the specified <code>File</code> line by line.
2220      * The default VM encoding and the default line ending will be used.
2221      *
2222      * @param file  the file to write to
2223      * @param lines  the lines to write, {@code null} entries produce blank lines
2224      * @throws IOException in case of an I/O error
2225      * @since 1.3
2226      */
2227     public static void writeLines(final File file, final Collection<?> lines) throws IOException {
2228         writeLines(file, null, lines, null, false);
2229     }
2230 
2231     /**
2232      * Writes the <code>toString()</code> value of each item in a collection to
2233      * the specified <code>File</code> line by line.
2234      * The default VM encoding and the default line ending will be used.
2235      *
2236      * @param file  the file to write to
2237      * @param lines  the lines to write, {@code null} entries produce blank lines
2238      * @param append if {@code true}, then the lines will be added to the
2239      * end of the file rather than overwriting
2240      * @throws IOException in case of an I/O error
2241      * @since 2.1
2242      */
2243     public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException {
2244         writeLines(file, null, lines, null, append);
2245     }
2246 
2247     /**
2248      * Writes the <code>toString()</code> value of each item in a collection to
2249      * the specified <code>File</code> line by line.
2250      * The specified character encoding and the line ending will be used.
2251      * <p>
2252      * NOTE: As from v1.3, the parent directories of the file will be created
2253      * if they do not exist.
2254      *
2255      * @param file  the file to write to
2256      * @param encoding  the encoding to use, {@code null} means platform default
2257      * @param lines  the lines to write, {@code null} entries produce blank lines
2258      * @param lineEnding  the line separator to use, {@code null} is system default
2259      * @throws IOException in case of an I/O error
2260      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
2261      * @since 1.1
2262      */
2263     public static void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding)
2264         throws IOException {
2265         writeLines(file, encoding, lines, lineEnding, false);
2266     }
2267 
2268     /**
2269      * Writes the <code>toString()</code> value of each item in a collection to
2270      * the specified <code>File</code> line by line.
2271      * The specified character encoding and the line ending will be used.
2272      *
2273      * @param file  the file to write to
2274      * @param encoding  the encoding to use, {@code null} means platform default
2275      * @param lines  the lines to write, {@code null} entries produce blank lines
2276      * @param lineEnding  the line separator to use, {@code null} is system default
2277      * @param append if {@code true}, then the lines will be added to the
2278      * end of the file rather than overwriting
2279      * @throws IOException in case of an I/O error
2280      * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
2281      * @since 2.1
2282      */
2283     public static void writeLines(final File file, final String encoding, final Collection<?> lines, final String lineEnding, final boolean append)
2284             throws IOException {
2285         FileOutputStream out = null;
2286         try {
2287             out = openOutputStream(file, append);
2288             final BufferedOutputStream buffer = new BufferedOutputStream(out);
2289             IOUtils.writeLines(lines, lineEnding, buffer, encoding);
2290             buffer.flush();
2291             out.close(); // don't swallow close Exception if copy completes normally
2292         } finally {
2293             IOUtils.closeQuietly(out);
2294         }
2295     }
2296 
2297     /**
2298      * Writes the <code>toString()</code> value of each item in a collection to
2299      * the specified <code>File</code> line by line.
2300      * The default VM encoding and the specified line ending will be used.
2301      *
2302      * @param file  the file to write to
2303      * @param lines  the lines to write, {@code null} entries produce blank lines
2304      * @param lineEnding  the line separator to use, {@code null} is system default
2305      * @throws IOException in case of an I/O error
2306      * @since 1.3
2307      */
2308     public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException {
2309         writeLines(file, null, lines, lineEnding, false);
2310     }
2311 
2312     /**
2313      * Writes the <code>toString()</code> value of each item in a collection to
2314      * the specified <code>File</code> line by line.
2315      * The default VM encoding and the specified line ending will be used.
2316      *
2317      * @param file  the file to write to
2318      * @param lines  the lines to write, {@code null} entries produce blank lines
2319      * @param lineEnding  the line separator to use, {@code null} is system default
2320      * @param append if {@code true}, then the lines will be added to the
2321      * end of the file rather than overwriting
2322      * @throws IOException in case of an I/O error
2323      * @since 2.1
2324      */
2325     public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append)
2326         throws IOException {
2327         writeLines(file, null, lines, lineEnding, append);
2328     }
2329 
2330     //-----------------------------------------------------------------------
2331     /**
2332      * Deletes a file. If file is a directory, delete it and all sub-directories.
2333      * <p>
2334      * The difference between File.delete() and this method are:
2335      * <ul>
2336      * <li>A directory to be deleted does not have to be empty.</li>
2337      * <li>You get exceptions when a file or directory cannot be deleted.
2338      *      (java.io.File methods returns a boolean)</li>
2339      * </ul>
2340      *
2341      * @param file  file or directory to delete, must not be {@code null}
2342      * @throws NullPointerException if the directory is {@code null}
2343      * @throws FileNotFoundException if the file was not found
2344      * @throws IOException in case deletion is unsuccessful
2345      */
2346     public static void forceDelete(final File file) throws IOException {
2347         if (file.isDirectory()) {
2348             deleteDirectory(file);
2349         } else {
2350             final boolean filePresent = file.exists();
2351             if (!file.delete()) {
2352                 if (!filePresent){
2353                     throw new FileNotFoundException("File does not exist: " + file);
2354                 }
2355                 final String message =
2356                     "Unable to delete file: " + file;
2357                 throw new IOException(message);
2358             }
2359         }
2360     }
2361 
2362     /**
2363      * Schedules a file to be deleted when JVM exits.
2364      * If file is directory delete it and all sub-directories.
2365      *
2366      * @param file  file or directory to delete, must not be {@code null}
2367      * @throws NullPointerException if the file is {@code null}
2368      * @throws IOException in case deletion is unsuccessful
2369      */
2370     public static void forceDeleteOnExit(final File file) throws IOException {
2371         if (file.isDirectory()) {
2372             deleteDirectoryOnExit(file);
2373         } else {
2374             file.deleteOnExit();
2375         }
2376     }
2377 
2378     /**
2379      * Schedules a directory recursively for deletion on JVM exit.
2380      *
2381      * @param directory  directory to delete, must not be {@code null}
2382      * @throws NullPointerException if the directory is {@code null}
2383      * @throws IOException in case deletion is unsuccessful
2384      */
2385     private static void deleteDirectoryOnExit(final File directory) throws IOException {
2386         if (!directory.exists()) {
2387             return;
2388         }
2389 
2390         directory.deleteOnExit();
2391         if (!isSymlink(directory)) {
2392             cleanDirectoryOnExit(directory);
2393         }
2394     }
2395 
2396     /**
2397      * Cleans a directory without deleting it.
2398      *
2399      * @param directory  directory to clean, must not be {@code null}
2400      * @throws NullPointerException if the directory is {@code null}
2401      * @throws IOException in case cleaning is unsuccessful
2402      */
2403     private static void cleanDirectoryOnExit(final File directory) throws IOException {
2404         if (!directory.exists()) {
2405             final String message = directory + " does not exist";
2406             throw new IllegalArgumentException(message);
2407         }
2408 
2409         if (!directory.isDirectory()) {
2410             final String message = directory + " is not a directory";
2411             throw new IllegalArgumentException(message);
2412         }
2413 
2414         final File[] files = directory.listFiles();
2415         if (files == null) {  // null if security restricted
2416             throw new IOException("Failed to list contents of " + directory);
2417         }
2418 
2419         IOException exception = null;
2420         for (final File file : files) {
2421             try {
2422                 forceDeleteOnExit(file);
2423             } catch (final IOException ioe) {
2424                 exception = ioe;
2425             }
2426         }
2427 
2428         if (null != exception) {
2429             throw exception;
2430         }
2431     }
2432 
2433     /**
2434      * Makes a directory, including any necessary but nonexistent parent
2435      * directories. If a file already exists with specified name but it is
2436      * not a directory then an IOException is thrown.
2437      * If the directory cannot be created (or does not already exist)
2438      * then an IOException is thrown.
2439      *
2440      * @param directory  directory to create, must not be {@code null}
2441      * @throws NullPointerException if the directory is {@code null}
2442      * @throws IOException if the directory cannot be created or the file already exists but is not a directory
2443      */
2444     public static void forceMkdir(final File directory) throws IOException {
2445         if (directory.exists()) {
2446             if (!directory.isDirectory()) {
2447                 final String message =
2448                     "File "
2449                         + directory
2450                         + " exists and is "
2451                         + "not a directory. Unable to create directory.";
2452                 throw new IOException(message);
2453             }
2454         } else {
2455             if (!directory.mkdirs()) {
2456                 // Double-check that some other thread or process hasn't made
2457                 // the directory in the background
2458                 if (!directory.isDirectory())
2459                 {
2460                     final String message =
2461                         "Unable to create directory " + directory;
2462                     throw new IOException(message);
2463                 }
2464             }
2465         }
2466     }
2467 
2468     /**
2469      * Makes any necessary but nonexistent parent directories for a given File. If the parent directory cannot be
2470      * created then an IOException is thrown.
2471      *
2472      * @param file
2473      *            file with parent to create, must not be {@code null}
2474      * @throws NullPointerException
2475      *             if the file is {@code null}
2476      * @throws IOException
2477      *             if the parent directory cannot be created
2478      * @since 2.5
2479      */
2480     public static void forceMkdirParent(final File file) throws IOException {
2481         final File parent = file.getParentFile();
2482         if (parent == null) {
2483             return;
2484         }
2485         forceMkdir(parent);
2486     }
2487 
2488     //-----------------------------------------------------------------------
2489     /**
2490      * Returns the size of the specified file or directory. If the provided
2491      * {@link File} is a regular file, then the file's length is returned.
2492      * If the argument is a directory, then the size of the directory is
2493      * calculated recursively. If a directory or subdirectory is security
2494      * restricted, its size will not be included.
2495      * <p>
2496      * Note that overflow is not detected, and the return value may be negative if
2497      * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative
2498      * method that does not overflow.
2499      *
2500      * @param file the regular file or directory to return the size
2501      *        of (must not be {@code null}).
2502      *
2503      * @return the length of the file, or recursive size of the directory,
2504      *         provided (in bytes).
2505      *
2506      * @throws NullPointerException if the file is {@code null}
2507      * @throws IllegalArgumentException if the file does not exist.
2508      *
2509      * @since 2.0
2510      */
2511     public static long sizeOf(final File file) {
2512 
2513         if (!file.exists()) {
2514             final String message = file + " does not exist";
2515             throw new IllegalArgumentException(message);
2516         }
2517 
2518         if (file.isDirectory()) {
2519             return sizeOfDirectory0(file); // private method; expects directory
2520         } else {
2521             return file.length();
2522         }
2523 
2524     }
2525 
2526     /**
2527      * Returns the size of the specified file or directory. If the provided
2528      * {@link File} is a regular file, then the file's length is returned.
2529      * If the argument is a directory, then the size of the directory is
2530      * calculated recursively. If a directory or subdirectory is security
2531      * restricted, its size will not be included.
2532      *
2533      * @param file the regular file or directory to return the size
2534      *        of (must not be {@code null}).
2535      *
2536      * @return the length of the file, or recursive size of the directory,
2537      *         provided (in bytes).
2538      *
2539      * @throws NullPointerException if the file is {@code null}
2540      * @throws IllegalArgumentException if the file does not exist.
2541      *
2542      * @since 2.4
2543      */
2544     public static BigInteger sizeOfAsBigInteger(final File file) {
2545 
2546         if (!file.exists()) {
2547             final String message = file + " does not exist";
2548             throw new IllegalArgumentException(message);
2549         }
2550 
2551         if (file.isDirectory()) {
2552             return sizeOfDirectoryBig0(file); // internal method
2553         } else {
2554             return BigInteger.valueOf(file.length());
2555         }
2556 
2557     }
2558 
2559     /**
2560      * Counts the size of a directory recursively (sum of the length of all files).
2561      * <p>
2562      * Note that overflow is not detected, and the return value may be negative if
2563      * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative
2564      * method that does not overflow.
2565      *
2566      * @param directory
2567      *            directory to inspect, must not be {@code null}
2568      * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total
2569      *         is greater than {@link Long#MAX_VALUE}.
2570      * @throws NullPointerException
2571      *             if the directory is {@code null}
2572      */
2573     public static long sizeOfDirectory(final File directory) {
2574         checkDirectory(directory);
2575         return sizeOfDirectory0(directory);
2576     }
2577 
2578     // Private method, must be invoked will a directory parameter
2579     private static long sizeOfDirectory0(final File directory) {
2580         final File[] files = directory.listFiles();
2581         if (files == null) {  // null if security restricted
2582             return 0L;
2583         }
2584         long size = 0;
2585 
2586         for (final File file : files) {
2587             try {
2588                 if (!isSymlink(file)) {
2589                     size += sizeOf0(file); // internal method
2590                     if (size < 0) {
2591                         break;
2592                     }
2593                 }
2594             } catch (final IOException ioe) {
2595                 // Ignore exceptions caught when asking if a File is a symlink.
2596             }
2597         }
2598 
2599         return size;
2600     }
2601 
2602     // Internal method - does not check existence
2603     private static long sizeOf0(File file) {
2604         if (file.isDirectory()) {
2605             return sizeOfDirectory0(file);
2606         } else {
2607             return file.length(); // will be 0 if file does not exist
2608         }
2609     }
2610 
2611     /**
2612      * Counts the size of a directory recursively (sum of the length of all files).
2613      *
2614      * @param directory
2615      *            directory to inspect, must not be {@code null}
2616      * @return size of directory in bytes, 0 if directory is security restricted.
2617      * @throws NullPointerException
2618      *             if the directory is {@code null}
2619      *  @since 2.4
2620      */
2621     public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) {
2622         checkDirectory(directory);
2623         return sizeOfDirectoryBig0(directory);
2624     }
2625 
2626     // Must be called with a directory
2627     private static BigInteger sizeOfDirectoryBig0(final File directory) {
2628         final File[] files = directory.listFiles();
2629         if (files == null) {  // null if security restricted
2630             return BigInteger.ZERO;
2631         }
2632         BigInteger size =  BigInteger.ZERO;
2633 
2634         for (final File file : files) {
2635             try {
2636                 if (!isSymlink(file)) {
2637                     size = size.add(sizeOfBig0(file));
2638                 }
2639             } catch (final IOException ioe) {
2640                 // Ignore exceptions caught when asking if a File is a symlink.
2641             }
2642         }
2643 
2644         return size;
2645     }
2646 
2647     // internal method; if file does not exist will return 0
2648     private static BigInteger sizeOfBig0(final File fileOrDir) {
2649         if (fileOrDir.isDirectory()) {
2650             return sizeOfDirectoryBig0(fileOrDir);
2651         } else {
2652             return BigInteger.valueOf(fileOrDir.length());
2653         }
2654     }
2655 
2656     /**
2657      * Checks that the given {@code File} exists and is a directory.
2658      *
2659      * @param directory The {@code File} to check.
2660      * @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
2661      */
2662     private static void checkDirectory(final File directory) {
2663         if (!directory.exists()) {
2664             throw new IllegalArgumentException(directory + " does not exist");
2665         }
2666         if (!directory.isDirectory()) {
2667             throw new IllegalArgumentException(directory + " is not a directory");
2668         }
2669     }
2670 
2671     //-----------------------------------------------------------------------
2672     /**
2673      * Tests if the specified <code>File</code> is newer than the reference
2674      * <code>File</code>.
2675      *
2676      * @param file  the <code>File</code> of which the modification date must
2677      * be compared, must not be {@code null}
2678      * @param reference  the <code>File</code> of which the modification date
2679      * is used, must not be {@code null}
2680      * @return true if the <code>File</code> exists and has been modified more
2681      * recently than the reference <code>File</code>
2682      * @throws IllegalArgumentException if the file is {@code null}
2683      * @throws IllegalArgumentException if the reference file is {@code null} or doesn't exist
2684      */
2685      public static boolean isFileNewer(final File file, final File reference) {
2686         if (reference == null) {
2687             throw new IllegalArgumentException("No specified reference file");
2688         }
2689         if (!reference.exists()) {
2690             throw new IllegalArgumentException("The reference file '"
2691                     + reference + "' doesn't exist");
2692         }
2693         return isFileNewer(file, reference.lastModified());
2694     }
2695 
2696     /**
2697      * Tests if the specified <code>File</code> is newer than the specified
2698      * <code>Date</code>.
2699      *
2700      * @param file  the <code>File</code> of which the modification date
2701      * must be compared, must not be {@code null}
2702      * @param date  the date reference, must not be {@code null}
2703      * @return true if the <code>File</code> exists and has been modified
2704      * after the given <code>Date</code>.
2705      * @throws IllegalArgumentException if the file is {@code null}
2706      * @throws IllegalArgumentException if the date is {@code null}
2707      */
2708     public static boolean isFileNewer(final File file, final Date date) {
2709         if (date == null) {
2710             throw new IllegalArgumentException("No specified date");
2711         }
2712         return isFileNewer(file, date.getTime());
2713     }
2714 
2715     /**
2716      * Tests if the specified <code>File</code> is newer than the specified
2717      * time reference.
2718      *
2719      * @param file  the <code>File</code> of which the modification date must
2720      * be compared, must not be {@code null}
2721      * @param timeMillis  the time reference measured in milliseconds since the
2722      * epoch (00:00:00 GMT, January 1, 1970)
2723      * @return true if the <code>File</code> exists and has been modified after
2724      * the given time reference.
2725      * @throws IllegalArgumentException if the file is {@code null}
2726      */
2727      public static boolean isFileNewer(final File file, final long timeMillis) {
2728         if (file == null) {
2729             throw new IllegalArgumentException("No specified file");
2730         }
2731         if (!file.exists()) {
2732             return false;
2733         }
2734         return file.lastModified() > timeMillis;
2735     }
2736 
2737 
2738     //-----------------------------------------------------------------------
2739     /**
2740      * Tests if the specified <code>File</code> is older than the reference
2741      * <code>File</code>.
2742      *
2743      * @param file  the <code>File</code> of which the modification date must
2744      * be compared, must not be {@code null}
2745      * @param reference  the <code>File</code> of which the modification date
2746      * is used, must not be {@code null}
2747      * @return true if the <code>File</code> exists and has been modified before
2748      * the reference <code>File</code>
2749      * @throws IllegalArgumentException if the file is {@code null}
2750      * @throws IllegalArgumentException if the reference file is {@code null} or doesn't exist
2751      */
2752      public static boolean isFileOlder(final File file, final File reference) {
2753         if (reference == null) {
2754             throw new IllegalArgumentException("No specified reference file");
2755         }
2756         if (!reference.exists()) {
2757             throw new IllegalArgumentException("The reference file '"
2758                     + reference + "' doesn't exist");
2759         }
2760         return isFileOlder(file, reference.lastModified());
2761     }
2762 
2763     /**
2764      * Tests if the specified <code>File</code> is older than the specified
2765      * <code>Date</code>.
2766      *
2767      * @param file  the <code>File</code> of which the modification date
2768      * must be compared, must not be {@code null}
2769      * @param date  the date reference, must not be {@code null}
2770      * @return true if the <code>File</code> exists and has been modified
2771      * before the given <code>Date</code>.
2772      * @throws IllegalArgumentException if the file is {@code null}
2773      * @throws IllegalArgumentException if the date is {@code null}
2774      */
2775     public static boolean isFileOlder(final File file, final Date date) {
2776         if (date == null) {
2777             throw new IllegalArgumentException("No specified date");
2778         }
2779         return isFileOlder(file, date.getTime());
2780     }
2781 
2782     /**
2783      * Tests if the specified <code>File</code> is older than the specified
2784      * time reference.
2785      *
2786      * @param file  the <code>File</code> of which the modification date must
2787      * be compared, must not be {@code null}
2788      * @param timeMillis  the time reference measured in milliseconds since the
2789      * epoch (00:00:00 GMT, January 1, 1970)
2790      * @return true if the <code>File</code> exists and has been modified before
2791      * the given time reference.
2792      * @throws IllegalArgumentException if the file is {@code null}
2793      */
2794      public static boolean isFileOlder(final File file, final long timeMillis) {
2795         if (file == null) {
2796             throw new IllegalArgumentException("No specified file");
2797         }
2798         if (!file.exists()) {
2799             return false;
2800         }
2801         return file.lastModified() < timeMillis;
2802     }
2803 
2804     //-----------------------------------------------------------------------
2805     /**
2806      * Computes the checksum of a file using the CRC32 checksum routine.
2807      * The value of the checksum is returned.
2808      *
2809      * @param file  the file to checksum, must not be {@code null}
2810      * @return the checksum value
2811      * @throws NullPointerException if the file or checksum is {@code null}
2812      * @throws IllegalArgumentException if the file is a directory
2813      * @throws IOException if an IO error occurs reading the file
2814      * @since 1.3
2815      */
2816     public static long checksumCRC32(final File file) throws IOException {
2817         final CRC32 crc = new CRC32();
2818         checksum(file, crc);
2819         return crc.getValue();
2820     }
2821 
2822     /**
2823      * Computes the checksum of a file using the specified checksum object.
2824      * Multiple files may be checked using one <code>Checksum</code> instance
2825      * if desired simply by reusing the same checksum object.
2826      * For example:
2827      * <pre>
2828      *   long csum = FileUtils.checksum(file, new CRC32()).getValue();
2829      * </pre>
2830      *
2831      * @param file  the file to checksum, must not be {@code null}
2832      * @param checksum  the checksum object to be used, must not be {@code null}
2833      * @return the checksum specified, updated with the content of the file
2834      * @throws NullPointerException if the file or checksum is {@code null}
2835      * @throws IllegalArgumentException if the file is a directory
2836      * @throws IOException if an IO error occurs reading the file
2837      * @since 1.3
2838      */
2839     public static Checksum checksum(final File file, final Checksum checksum) throws IOException {
2840         if (file.isDirectory()) {
2841             throw new IllegalArgumentException("Checksums can't be computed on directories");
2842         }
2843         InputStream in = null;
2844         try {
2845             in = new CheckedInputStream(new FileInputStream(file), checksum);
2846             IOUtils.copy(in, new NullOutputStream());
2847         } finally {
2848             IOUtils.closeQuietly(in);
2849         }
2850         return checksum;
2851     }
2852 
2853     /**
2854      * Moves a directory.
2855      * <p>
2856      * When the destination directory is on another file system, do a "copy and delete".
2857      *
2858      * @param srcDir the directory to be moved
2859      * @param destDir the destination directory
2860      * @throws NullPointerException if source or destination is {@code null}
2861      * @throws FileExistsException if the destination directory exists
2862      * @throws IOException if source or destination is invalid
2863      * @throws IOException if an IO error occurs moving the file
2864      * @since 1.4
2865      */
2866     public static void moveDirectory(final File srcDir, final File destDir) throws IOException {
2867         if (srcDir == null) {
2868             throw new NullPointerException("Source must not be null");
2869         }
2870         if (destDir == null) {
2871             throw new NullPointerException("Destination must not be null");
2872         }
2873         if (!srcDir.exists()) {
2874             throw new FileNotFoundException("Source '" + srcDir + "' does not exist");
2875         }
2876         if (!srcDir.isDirectory()) {
2877             throw new IOException("Source '" + srcDir + "' is not a directory");
2878         }
2879         if (destDir.exists()) {
2880             throw new FileExistsException("Destination '" + destDir + "' already exists");
2881         }
2882         final boolean rename = srcDir.renameTo(destDir);
2883         if (!rename) {
2884             if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) {
2885                 throw new IOException("Cannot move directory: "+srcDir+" to a subdirectory of itself: "+destDir);
2886             }
2887             copyDirectory( srcDir, destDir );
2888             deleteDirectory( srcDir );
2889             if (srcDir.exists()) {
2890                 throw new IOException("Failed to delete original directory '" + srcDir +
2891                         "' after copy to '" + destDir + "'");
2892             }
2893         }
2894     }
2895 
2896     /**
2897      * Moves a directory to another directory.
2898      *
2899      * @param src the file to be moved
2900      * @param destDir the destination file
2901      * @param createDestDir If {@code true} create the destination directory,
2902      * otherwise if {@code false} throw an IOException
2903      * @throws NullPointerException if source or destination is {@code null}
2904      * @throws FileExistsException if the directory exists in the destination directory
2905      * @throws IOException if source or destination is invalid
2906      * @throws IOException if an IO error occurs moving the file
2907      * @since 1.4
2908      */
2909     public static void moveDirectoryToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException {
2910         if (src == null) {
2911             throw new NullPointerException("Source must not be null");
2912         }
2913         if (destDir == null) {
2914             throw new NullPointerException("Destination directory must not be null");
2915         }
2916         if (!destDir.exists() && createDestDir) {
2917             destDir.mkdirs();
2918         }
2919         if (!destDir.exists()) {
2920             throw new FileNotFoundException("Destination directory '" + destDir +
2921                     "' does not exist [createDestDir=" + createDestDir +"]");
2922         }
2923         if (!destDir.isDirectory()) {
2924             throw new IOException("Destination '" + destDir + "' is not a directory");
2925         }
2926         moveDirectory(src, new File(destDir, src.getName()));
2927 
2928     }
2929 
2930     /**
2931      * Moves a file.
2932      * <p>
2933      * When the destination file is on another file system, do a "copy and delete".
2934      *
2935      * @param srcFile the file to be moved
2936      * @param destFile the destination file
2937      * @throws NullPointerException if source or destination is {@code null}
2938      * @throws FileExistsException if the destination file exists
2939      * @throws IOException if source or destination is invalid
2940      * @throws IOException if an IO error occurs moving the file
2941      * @since 1.4
2942      */
2943     public static void moveFile(final File srcFile, final File destFile) throws IOException {
2944         if (srcFile == null) {
2945             throw new NullPointerException("Source must not be null");
2946         }
2947         if (destFile == null) {
2948             throw new NullPointerException("Destination must not be null");
2949         }
2950         if (!srcFile.exists()) {
2951             throw new FileNotFoundException("Source '" + srcFile + "' does not exist");
2952         }
2953         if (srcFile.isDirectory()) {
2954             throw new IOException("Source '" + srcFile + "' is a directory");
2955         }
2956         if (destFile.exists()) {
2957             throw new FileExistsException("Destination '" + destFile + "' already exists");
2958         }
2959         if (destFile.isDirectory()) {
2960             throw new IOException("Destination '" + destFile + "' is a directory");
2961         }
2962         final boolean rename = srcFile.renameTo(destFile);
2963         if (!rename) {
2964             copyFile( srcFile, destFile );
2965             if (!srcFile.delete()) {
2966                 FileUtils.deleteQuietly(destFile);
2967                 throw new IOException("Failed to delete original file '" + srcFile +
2968                         "' after copy to '" + destFile + "'");
2969             }
2970         }
2971     }
2972 
2973     /**
2974      * Moves a file to a directory.
2975      *
2976      * @param srcFile the file to be moved
2977      * @param destDir the destination file
2978      * @param createDestDir If {@code true} create the destination directory,
2979      * otherwise if {@code false} throw an IOException
2980      * @throws NullPointerException if source or destination is {@code null}
2981      * @throws FileExistsException if the destination file exists
2982      * @throws IOException if source or destination is invalid
2983      * @throws IOException if an IO error occurs moving the file
2984      * @since 1.4
2985      */
2986     public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException {
2987         if (srcFile == null) {
2988             throw new NullPointerException("Source must not be null");
2989         }
2990         if (destDir == null) {
2991             throw new NullPointerException("Destination directory must not be null");
2992         }
2993         if (!destDir.exists() && createDestDir) {
2994             destDir.mkdirs();
2995         }
2996         if (!destDir.exists()) {
2997             throw new FileNotFoundException("Destination directory '" + destDir +
2998                     "' does not exist [createDestDir=" + createDestDir +"]");
2999         }
3000         if (!destDir.isDirectory()) {
3001             throw new IOException("Destination '" + destDir + "' is not a directory");
3002         }
3003         moveFile(srcFile, new File(destDir, srcFile.getName()));
3004     }
3005 
3006     /**
3007      * Moves a file or directory to the destination directory.
3008      * <p>
3009      * When the destination is on another file system, do a "copy and delete".
3010      *
3011      * @param src the file or directory to be moved
3012      * @param destDir the destination directory
3013      * @param createDestDir If {@code true} create the destination directory,
3014      * otherwise if {@code false} throw an IOException
3015      * @throws NullPointerException if source or destination is {@code null}
3016      * @throws FileExistsException if the directory or file exists in the destination directory
3017      * @throws IOException if source or destination is invalid
3018      * @throws IOException if an IO error occurs moving the file
3019      * @since 1.4
3020      */
3021     public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException {
3022         if (src == null) {
3023             throw new NullPointerException("Source must not be null");
3024         }
3025         if (destDir == null) {
3026             throw new NullPointerException("Destination must not be null");
3027         }
3028         if (!src.exists()) {
3029             throw new FileNotFoundException("Source '" + src + "' does not exist");
3030         }
3031         if (src.isDirectory()) {
3032             moveDirectoryToDirectory(src, destDir, createDestDir);
3033         } else {
3034             moveFileToDirectory(src, destDir, createDestDir);
3035         }
3036     }
3037 
3038     /**
3039      * Determines whether the specified file is a Symbolic Link rather than an actual file.
3040      * <p>
3041      * Will not return true if there is a Symbolic Link anywhere in the path,
3042      * only if the specific file is.
3043      * <p>
3044      * <b>Note:</b> the current implementation always returns {@code false} if the system
3045      * is detected as Windows using {@link FilenameUtils#isSystemWindows()}
3046      * <p>
3047      * For code that runs on Java 1.7 or later, use the following method instead:
3048      * <br>
3049      * {@code boolean java.nio.file.Files.isSymbolicLink(Path path)}
3050      * @param file the file to check
3051      * @return true if the file is a Symbolic Link
3052      * @throws IOException if an IO error occurs while checking the file
3053      * @since 2.0
3054      */
3055     public static boolean isSymlink(final File file) throws IOException {
3056         if (file == null) {
3057             throw new NullPointerException("File must not be null");
3058         }
3059         if (FilenameUtils.isSystemWindows()) {
3060             return false;
3061         }
3062         File fileInCanonicalDir = null;
3063         if (file.getParent() == null) {
3064             fileInCanonicalDir = file;
3065         } else {
3066             final File canonicalDir = file.getParentFile().getCanonicalFile();
3067             fileInCanonicalDir = new File(canonicalDir, file.getName());
3068         }
3069 
3070         if (fileInCanonicalDir.getCanonicalFile().equals(fileInCanonicalDir.getAbsoluteFile())) {
3071             return false;
3072         } else {
3073             return true;
3074         }
3075     }
3076 
3077 }