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