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