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