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
97 * <li>reading from a file
98 * <li>make a directory including parent directories
99 * <li>copying files and directories
100 * <li>deleting files and directories
101 * <li>converting to and from a URL
102 * <li>listing files and directories by filter and extension
103 * <li>comparing file content
104 * <li>file last changed date
105 * <li>calculating a checksum
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.
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 * Getsv the path to the system temporary directory.
1554 *
1555 * WARNING: this method relies on the Java system property 'java.io.tmpdir'
1556 * which may or may not have a trailing file separator.
1557 * This can affect code that uses String processing to manipulate pathnames rather
1558 * than the standard libary methods in classes such as {@link File}
1559 *
1560 * @return the path to the system temporary directory as a String
1561 * @since 2.0
1562 */
1563 public static String getTempDirectoryPath() {
1564 return System.getProperty("java.io.tmpdir");
1565 }
1566
1567 /**
1568 * Gets a {@link File} representing the user's home directory.
1569 *
1570 * @return the user's home directory.
1571 * @since 2.0
1572 */
1573 public static File getUserDirectory() {
1574 return new File(getUserDirectoryPath());
1575 }
1576
1577 /**
1578 * Gets the path to the user's home directory.
1579 *
1580 * @return the path to the user's home directory.
1581 * @since 2.0
1582 */
1583 public static String getUserDirectoryPath() {
1584 return System.getProperty("user.home");
1585 }
1586
1587 /**
1588 * Tests whether the specified {@link File} is a directory or not. Implemented as a
1589 * null-safe delegate to {@link Files#isDirectory(Path path, LinkOption... options)}.
1590 *
1591 * @param file the path to the file.
1592 * @param options options indicating how symbolic links are handled
1593 * @return {@code true} if the file is a directory; {@code false} if
1594 * the path is null, the file does not exist, is not a directory, or it cannot
1595 * be determined if the file is a directory or not.
1596 * @throws SecurityException In the case of the default provider, and a security manager is installed, the
1597 * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read
1598 * access to the directory.
1599 * @since 2.9.0
1600 */
1601 public static boolean isDirectory(final File file, final LinkOption... options) {
1602 return file != null && Files.isDirectory(file.toPath(), options);
1603 }
1604
1605 /**
1606 * Tests whether the directory is empty.
1607 *
1608 * @param directory the directory to query.
1609 * @return whether the directory is empty.
1610 * @throws IOException if an I/O error occurs.
1611 * @throws NotDirectoryException if the file could not otherwise be opened because it is not a directory
1612 * <em>(optional specific exception)</em>.
1613 * @since 2.9.0
1614 */
1615 public static boolean isEmptyDirectory(final File directory) throws IOException {
1616 return PathUtils.isEmptyDirectory(directory.toPath());
1617 }
1618
1619 /**
1620 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate}
1621 * at the end of day.
1622 *
1623 * <p>
1624 * Note: The input date is assumed to be in the system default time-zone with the time
1625 * part set to the current time. To use a non-default time-zone use the method
1626 * {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId)
1627 * isFileNewer(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where
1628 * {@code zoneId} is a valid {@link ZoneId}.
1629 * </p>
1630 *
1631 * @param file the {@link File} of which the modification date must be compared.
1632 * @param chronoLocalDate the date reference.
1633 * @return true if the {@link File} exists and has been modified after the given
1634 * {@link ChronoLocalDate} at the current time.
1635 * @throws UncheckedIOException if an I/O error occurs
1636 * @throws NullPointerException if the file or local date is {@code null}.
1637 * @since 2.8.0
1638 */
1639 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate) {
1640 return isFileNewer(file, chronoLocalDate, LocalTime.MAX);
1641 }
1642
1643 /**
1644 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate}
1645 * at the specified time.
1646 *
1647 * <p>
1648 * Note: The input date and time are assumed to be in the system default time-zone. To use a
1649 * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId)
1650 * isFileNewer(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid
1651 * {@link ZoneId}.
1652 * </p>
1653 *
1654 * @param file the {@link File} of which the modification date must be compared.
1655 * @param chronoLocalDate the date reference.
1656 * @param localTime the time reference.
1657 * @return true if the {@link File} exists and has been modified after the given
1658 * {@link ChronoLocalDate} at the given time.
1659 * @throws UncheckedIOException if an I/O error occurs
1660 * @throws NullPointerException if the file, local date or zone ID is {@code null}.
1661 * @since 2.8.0
1662 */
1663 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) {
1664 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
1665 Objects.requireNonNull(localTime, "localTime");
1666 return isFileNewer(file, chronoLocalDate.atTime(localTime));
1667 }
1668
1669 /**
1670 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDate} at the specified
1671 * {@link OffsetTime}.
1672 *
1673 * @param file the {@link File} of which the modification date must be compared
1674 * @param chronoLocalDate the date reference
1675 * @param offsetTime the time reference
1676 * @return true if the {@link File} exists and has been modified after the given {@link ChronoLocalDate} at the given
1677 * {@link OffsetTime}.
1678 * @throws UncheckedIOException if an I/O error occurs
1679 * @throws NullPointerException if the file, local date or zone ID is {@code null}
1680 * @since 2.12.0
1681 */
1682 public static boolean isFileNewer(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) {
1683 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
1684 Objects.requireNonNull(offsetTime, "offsetTime");
1685 return isFileNewer(file, chronoLocalDate.atTime(offsetTime.toLocalTime()));
1686 }
1687
1688 /**
1689 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDateTime}
1690 * at the system-default time zone.
1691 *
1692 * <p>
1693 * Note: The input date and time is assumed to be in the system default time-zone. To use a
1694 * non-default time-zone use the method {@link #isFileNewer(File, ChronoLocalDateTime, ZoneId)
1695 * isFileNewer(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid
1696 * {@link ZoneId}.
1697 * </p>
1698 *
1699 * @param file the {@link File} of which the modification date must be compared.
1700 * @param chronoLocalDateTime the date reference.
1701 * @return true if the {@link File} exists and has been modified after the given
1702 * {@link ChronoLocalDateTime} at the system-default time zone.
1703 * @throws UncheckedIOException if an I/O error occurs
1704 * @throws NullPointerException if the file or local date time is {@code null}.
1705 * @since 2.8.0
1706 */
1707 public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) {
1708 return isFileNewer(file, chronoLocalDateTime, ZoneId.systemDefault());
1709 }
1710
1711 /**
1712 * Tests if the specified {@link File} is newer than the specified {@link ChronoLocalDateTime}
1713 * at the specified {@link ZoneId}.
1714 *
1715 * @param file the {@link File} of which the modification date must be compared.
1716 * @param chronoLocalDateTime the date reference.
1717 * @param zoneId the time zone.
1718 * @return true if the {@link File} exists and has been modified after the given
1719 * {@link ChronoLocalDateTime} at the given {@link ZoneId}.
1720 * @throws UncheckedIOException if an I/O error occurs
1721 * @throws NullPointerException if the file, local date time or zone ID is {@code null}.
1722 * @since 2.8.0
1723 */
1724 public static boolean isFileNewer(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) {
1725 Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime");
1726 Objects.requireNonNull(zoneId, "zoneId");
1727 return isFileNewer(file, chronoLocalDateTime.atZone(zoneId));
1728 }
1729
1730 /**
1731 * Tests if the specified {@link File} is newer than the specified {@link ChronoZonedDateTime}.
1732 *
1733 * @param file the {@link File} of which the modification date must be compared.
1734 * @param chronoZonedDateTime the date reference.
1735 * @return true if the {@link File} exists and has been modified after the given
1736 * {@link ChronoZonedDateTime}.
1737 * @throws NullPointerException if the file or zoned date time is {@code null}.
1738 * @throws UncheckedIOException if an I/O error occurs
1739 * @since 2.8.0
1740 */
1741 public static boolean isFileNewer(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) {
1742 Objects.requireNonNull(file, PROTOCOL_FILE);
1743 Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
1744 return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), chronoZonedDateTime));
1745 }
1746
1747 /**
1748 * Tests if the specified {@link File} is newer than the specified {@link Date}.
1749 *
1750 * @param file the {@link File} of which the modification date must be compared.
1751 * @param date the date reference.
1752 * @return true if the {@link File} exists and has been modified
1753 * after the given {@link Date}.
1754 * @throws UncheckedIOException if an I/O error occurs
1755 * @throws NullPointerException if the file or date is {@code null}.
1756 */
1757 public static boolean isFileNewer(final File file, final Date date) {
1758 Objects.requireNonNull(date, "date");
1759 return isFileNewer(file, date.getTime());
1760 }
1761
1762 /**
1763 * Tests if the specified {@link File} is newer than the reference {@link File}.
1764 *
1765 * @param file the {@link File} of which the modification date must be compared.
1766 * @param reference the {@link File} of which the modification date is used.
1767 * @return true if the {@link File} exists and has been modified more
1768 * recently than the reference {@link File}.
1769 * @throws NullPointerException if the file or reference file is {@code null}.
1770 * @throws UncheckedIOException if the reference file doesn't exist.
1771 */
1772 public static boolean isFileNewer(final File file, final File reference) {
1773 return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), reference.toPath()));
1774 }
1775
1776 /**
1777 * Tests if the specified {@link File} is newer than the specified {@link FileTime}.
1778 *
1779 * @param file the {@link File} of which the modification date must be compared.
1780 * @param fileTime the file time reference.
1781 * @return true if the {@link File} exists and has been modified after the given {@link FileTime}.
1782 * @throws IOException if an I/O error occurs.
1783 * @throws NullPointerException if the file or local date is {@code null}.
1784 * @since 2.12.0
1785 */
1786 public static boolean isFileNewer(final File file, final FileTime fileTime) throws IOException {
1787 Objects.requireNonNull(file, PROTOCOL_FILE);
1788 return PathUtils.isNewer(file.toPath(), fileTime);
1789 }
1790
1791 /**
1792 * Tests if the specified {@link File} is newer than the specified {@link Instant}.
1793 *
1794 * @param file the {@link File} of which the modification date must be compared.
1795 * @param instant the date reference.
1796 * @return true if the {@link File} exists and has been modified after the given {@link Instant}.
1797 * @throws NullPointerException if the file or instant is {@code null}.
1798 * @throws UncheckedIOException if an I/O error occurs
1799 * @since 2.8.0
1800 */
1801 public static boolean isFileNewer(final File file, final Instant instant) {
1802 Objects.requireNonNull(instant, "instant");
1803 return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), instant));
1804 }
1805
1806 /**
1807 * Tests if the specified {@link File} is newer than the specified time reference.
1808 *
1809 * @param file the {@link File} of which the modification date must be compared.
1810 * @param timeMillis the time reference measured in milliseconds since the
1811 * epoch (00:00:00 GMT, January 1, 1970).
1812 * @return true if the {@link File} exists and has been modified after the given time reference.
1813 * @throws UncheckedIOException if an I/O error occurs
1814 * @throws NullPointerException if the file is {@code null}.
1815 */
1816 public static boolean isFileNewer(final File file, final long timeMillis) {
1817 Objects.requireNonNull(file, PROTOCOL_FILE);
1818 return Uncheck.getAsBoolean(() -> PathUtils.isNewer(file.toPath(), timeMillis));
1819 }
1820
1821 /**
1822 * Tests if the specified {@link File} is newer than the specified {@link OffsetDateTime}.
1823 *
1824 * @param file the {@link File} of which the modification date must be compared
1825 * @param offsetDateTime the date reference
1826 * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}.
1827 * @throws UncheckedIOException if an I/O error occurs
1828 * @throws NullPointerException if the file or zoned date time is {@code null}
1829 * @since 2.12.0
1830 */
1831 public static boolean isFileNewer(final File file, final OffsetDateTime offsetDateTime) {
1832 Objects.requireNonNull(offsetDateTime, "offsetDateTime");
1833 return isFileNewer(file, offsetDateTime.toInstant());
1834 }
1835
1836 /**
1837 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate}
1838 * at the end of day.
1839 *
1840 * <p>
1841 * Note: The input date is assumed to be in the system default time-zone with the time
1842 * part set to the current time. To use a non-default time-zone use the method
1843 * {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
1844 * isFileOlder(file, chronoLocalDate.atTime(LocalTime.now(zoneId)), zoneId)} where
1845 * {@code zoneId} is a valid {@link ZoneId}.
1846 * </p>
1847 *
1848 * @param file the {@link File} of which the modification date must be compared.
1849 * @param chronoLocalDate the date reference.
1850 * @return true if the {@link File} exists and has been modified before the given
1851 * {@link ChronoLocalDate} at the current time.
1852 * @throws NullPointerException if the file or local date is {@code null}.
1853 * @throws UncheckedIOException if an I/O error occurs
1854 * @see ZoneId#systemDefault()
1855 * @see LocalTime#now()
1856 * @since 2.8.0
1857 */
1858 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate) {
1859 return isFileOlder(file, chronoLocalDate, LocalTime.MAX);
1860 }
1861
1862 /**
1863 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate}
1864 * at the specified {@link LocalTime}.
1865 *
1866 * <p>
1867 * Note: The input date and time are assumed to be in the system default time-zone. To use a
1868 * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
1869 * isFileOlder(file, chronoLocalDate.atTime(localTime), zoneId)} where {@code zoneId} is a valid
1870 * {@link ZoneId}.
1871 * </p>
1872 *
1873 * @param file the {@link File} of which the modification date must be compared.
1874 * @param chronoLocalDate the date reference.
1875 * @param localTime the time reference.
1876 * @return true if the {@link File} exists and has been modified before the
1877 * given {@link ChronoLocalDate} at the specified time.
1878 * @throws UncheckedIOException if an I/O error occurs
1879 * @throws NullPointerException if the file, local date or local time is {@code null}.
1880 * @see ZoneId#systemDefault()
1881 * @since 2.8.0
1882 */
1883 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final LocalTime localTime) {
1884 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
1885 Objects.requireNonNull(localTime, "localTime");
1886 return isFileOlder(file, chronoLocalDate.atTime(localTime));
1887 }
1888
1889 /**
1890 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDate} at the specified
1891 * {@link OffsetTime}.
1892 *
1893 * @param file the {@link File} of which the modification date must be compared
1894 * @param chronoLocalDate the date reference
1895 * @param offsetTime the time reference
1896 * @return true if the {@link File} exists and has been modified after the given {@link ChronoLocalDate} at the given
1897 * {@link OffsetTime}.
1898 * @throws NullPointerException if the file, local date or zone ID is {@code null}
1899 * @throws UncheckedIOException if an I/O error occurs
1900 * @since 2.12.0
1901 */
1902 public static boolean isFileOlder(final File file, final ChronoLocalDate chronoLocalDate, final OffsetTime offsetTime) {
1903 Objects.requireNonNull(chronoLocalDate, "chronoLocalDate");
1904 Objects.requireNonNull(offsetTime, "offsetTime");
1905 return isFileOlder(file, chronoLocalDate.atTime(offsetTime.toLocalTime()));
1906 }
1907
1908 /**
1909 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime}
1910 * at the system-default time zone.
1911 *
1912 * <p>
1913 * Note: The input date and time is assumed to be in the system default time-zone. To use a
1914 * non-default time-zone use the method {@link #isFileOlder(File, ChronoLocalDateTime, ZoneId)
1915 * isFileOlder(file, chronoLocalDateTime, zoneId)} where {@code zoneId} is a valid
1916 * {@link ZoneId}.
1917 * </p>
1918 *
1919 * @param file the {@link File} of which the modification date must be compared.
1920 * @param chronoLocalDateTime the date reference.
1921 * @return true if the {@link File} exists and has been modified before the given
1922 * {@link ChronoLocalDateTime} at the system-default time zone.
1923 * @throws NullPointerException if the file or local date time is {@code null}.
1924 * @throws UncheckedIOException if an I/O error occurs
1925 * @see ZoneId#systemDefault()
1926 * @since 2.8.0
1927 */
1928 public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime) {
1929 return isFileOlder(file, chronoLocalDateTime, ZoneId.systemDefault());
1930 }
1931
1932 /**
1933 * Tests if the specified {@link File} is older than the specified {@link ChronoLocalDateTime}
1934 * at the specified {@link ZoneId}.
1935 *
1936 * @param file the {@link File} of which the modification date must be compared.
1937 * @param chronoLocalDateTime the date reference.
1938 * @param zoneId the time zone.
1939 * @return true if the {@link File} exists and has been modified before the given
1940 * {@link ChronoLocalDateTime} at the given {@link ZoneId}.
1941 * @throws NullPointerException if the file, local date time or zone ID is {@code null}.
1942 * @throws UncheckedIOException if an I/O error occurs
1943 * @since 2.8.0
1944 */
1945 public static boolean isFileOlder(final File file, final ChronoLocalDateTime<?> chronoLocalDateTime, final ZoneId zoneId) {
1946 Objects.requireNonNull(chronoLocalDateTime, "chronoLocalDateTime");
1947 Objects.requireNonNull(zoneId, "zoneId");
1948 return isFileOlder(file, chronoLocalDateTime.atZone(zoneId));
1949 }
1950
1951 /**
1952 * Tests if the specified {@link File} is older than the specified {@link ChronoZonedDateTime}.
1953 *
1954 * @param file the {@link File} of which the modification date must be compared.
1955 * @param chronoZonedDateTime the date reference.
1956 * @return true if the {@link File} exists and has been modified before the given
1957 * {@link ChronoZonedDateTime}.
1958 * @throws NullPointerException if the file or zoned date time is {@code null}.
1959 * @throws UncheckedIOException if an I/O error occurs
1960 * @since 2.8.0
1961 */
1962 public static boolean isFileOlder(final File file, final ChronoZonedDateTime<?> chronoZonedDateTime) {
1963 Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
1964 return isFileOlder(file, chronoZonedDateTime.toInstant());
1965 }
1966
1967 /**
1968 * Tests if the specified {@link File} is older than the specified {@link Date}.
1969 *
1970 * @param file the {@link File} of which the modification date must be compared.
1971 * @param date the date reference.
1972 * @return true if the {@link File} exists and has been modified before the given {@link Date}.
1973 * @throws NullPointerException if the file or date is {@code null}.
1974 * @throws UncheckedIOException if an I/O error occurs
1975 */
1976 public static boolean isFileOlder(final File file, final Date date) {
1977 Objects.requireNonNull(date, "date");
1978 return isFileOlder(file, date.getTime());
1979 }
1980
1981 /**
1982 * Tests if the specified {@link File} is older than the reference {@link File}.
1983 *
1984 * @param file the {@link File} of which the modification date must be compared.
1985 * @param reference the {@link File} of which the modification date is used.
1986 * @return true if the {@link File} exists and has been modified before the reference {@link File}.
1987 * @throws NullPointerException if the file or reference file is {@code null}.
1988 * @throws FileNotFoundException if the reference file doesn't exist.
1989 * @throws UncheckedIOException if an I/O error occurs
1990 */
1991 public static boolean isFileOlder(final File file, final File reference) throws FileNotFoundException {
1992 return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), reference.toPath()));
1993 }
1994
1995 /**
1996 * Tests if the specified {@link File} is older than the specified {@link FileTime}.
1997 *
1998 * @param file the {@link File} of which the modification date must be compared.
1999 * @param fileTime the file time reference.
2000 * @return true if the {@link File} exists and has been modified before the given {@link FileTime}.
2001 * @throws IOException if an I/O error occurs.
2002 * @throws NullPointerException if the file or local date is {@code null}.
2003 * @since 2.12.0
2004 */
2005 public static boolean isFileOlder(final File file, final FileTime fileTime) throws IOException {
2006 Objects.requireNonNull(file, PROTOCOL_FILE);
2007 return PathUtils.isOlder(file.toPath(), fileTime);
2008 }
2009
2010 /**
2011 * Tests if the specified {@link File} is older than the specified {@link Instant}.
2012 *
2013 * @param file the {@link File} of which the modification date must be compared.
2014 * @param instant the date reference.
2015 * @return true if the {@link File} exists and has been modified before the given {@link Instant}.
2016 * @throws NullPointerException if the file or instant is {@code null}.
2017 * @since 2.8.0
2018 */
2019 public static boolean isFileOlder(final File file, final Instant instant) {
2020 Objects.requireNonNull(instant, "instant");
2021 return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), instant));
2022 }
2023
2024 /**
2025 * Tests if the specified {@link File} is older than the specified time reference.
2026 *
2027 * @param file the {@link File} of which the modification date must be compared.
2028 * @param timeMillis the time reference measured in milliseconds since the
2029 * epoch (00:00:00 GMT, January 1, 1970).
2030 * @return true if the {@link File} exists and has been modified before the given time reference.
2031 * @throws NullPointerException if the file is {@code null}.
2032 * @throws UncheckedIOException if an I/O error occurs
2033 */
2034 public static boolean isFileOlder(final File file, final long timeMillis) {
2035 Objects.requireNonNull(file, PROTOCOL_FILE);
2036 return Uncheck.getAsBoolean(() -> PathUtils.isOlder(file.toPath(), timeMillis));
2037 }
2038
2039 /**
2040 * Tests if the specified {@link File} is older than the specified {@link OffsetDateTime}.
2041 *
2042 * @param file the {@link File} of which the modification date must be compared
2043 * @param offsetDateTime the date reference
2044 * @return true if the {@link File} exists and has been modified before the given {@link OffsetDateTime}.
2045 * @throws NullPointerException if the file or zoned date time is {@code null}
2046 * @since 2.12.0
2047 */
2048 public static boolean isFileOlder(final File file, final OffsetDateTime offsetDateTime) {
2049 Objects.requireNonNull(offsetDateTime, "offsetDateTime");
2050 return isFileOlder(file, offsetDateTime.toInstant());
2051 }
2052
2053 /**
2054 * Tests whether the given URL is a file URL.
2055 *
2056 * @param url The URL to test.
2057 * @return Whether the given URL is a file URL.
2058 */
2059 private static boolean isFileProtocol(final URL url) {
2060 return PROTOCOL_FILE.equalsIgnoreCase(url.getProtocol());
2061 }
2062
2063 /**
2064 * Tests whether the specified {@link File} is a regular file or not. Implemented as a
2065 * null-safe delegate to {@link Files#isRegularFile(Path path, LinkOption... options)}.
2066 *
2067 * @param file the path to the file.
2068 * @param options options indicating how symbolic links are handled
2069 * @return {@code true} if the file is a regular file; {@code false} if
2070 * the path is null, the file does not exist, is not a regular file, or it cannot
2071 * be determined if the file is a regular file or not.
2072 * @throws SecurityException In the case of the default provider, and a security manager is installed, the
2073 * {@link SecurityManager#checkRead(String) checkRead} method is invoked to check read
2074 * access to the directory.
2075 * @since 2.9.0
2076 */
2077 public static boolean isRegularFile(final File file, final LinkOption... options) {
2078 return file != null && Files.isRegularFile(file.toPath(), options);
2079 }
2080
2081 /**
2082 * Tests whether the specified file is a symbolic link rather than an actual file.
2083 * <p>
2084 * This method delegates to {@link Files#isSymbolicLink(Path path)}
2085 * </p>
2086 *
2087 * @param file the file to test, may be null.
2088 * @return true if the file is a symbolic link, see {@link Files#isSymbolicLink(Path path)}.
2089 * @since 2.0
2090 * @see Files#isSymbolicLink(Path)
2091 */
2092 public static boolean isSymlink(final File file) {
2093 return file != null && Files.isSymbolicLink(file.toPath());
2094 }
2095
2096 /**
2097 * Iterates over the files in given directory (and optionally
2098 * its subdirectories).
2099 * <p>
2100 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
2101 * </p>
2102 * <p>
2103 * All files found are filtered by an IOFileFilter.
2104 * </p>
2105 *
2106 * @param directory The directory to search.
2107 * @param fileFilter filter to apply when finding files.
2108 * @param dirFilter optional filter to apply when finding subdirectories.
2109 * If this parameter is {@code null}, subdirectories will not be included in the
2110 * search. Use TrueFileFilter.INSTANCE to match all directories.
2111 * @return an iterator of {@link File} for the matching files.
2112 * @see org.apache.commons.io.filefilter.FileFilterUtils
2113 * @see org.apache.commons.io.filefilter.NameFileFilter
2114 * @since 1.2
2115 */
2116 public static Iterator<File> iterateFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
2117 return listFiles(directory, fileFilter, dirFilter).iterator();
2118 }
2119
2120 /**
2121 * Iterates over the files in a given directory (and optionally
2122 * its subdirectories) which match an array of extensions.
2123 * <p>
2124 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
2125 * </p>
2126 *
2127 * @param directory The directory to search.
2128 * @param extensions an array of extensions, for example, <code>{"java", "xml"}</code>. If this
2129 * parameter is {@code null}, all files are returned.
2130 * @param recursive if true all subdirectories are searched as well.
2131 * @return an iterator of {@link File} with the matching files.
2132 * @since 1.2
2133 */
2134 public static Iterator<File> iterateFiles(final File directory, final String[] extensions, final boolean recursive) {
2135 return StreamIterator.iterator(Uncheck.get(() -> streamFiles(directory, recursive, extensions)));
2136 }
2137
2138 /**
2139 * Iterates over the files in given directory (and optionally
2140 * its subdirectories).
2141 * <p>
2142 * The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
2143 * </p>
2144 * <p>
2145 * All files found are filtered by an IOFileFilter.
2146 * </p>
2147 * <p>
2148 * The resulting iterator includes the subdirectories themselves.
2149 * </p>
2150 *
2151 * @param directory The directory to search.
2152 * @param fileFilter filter to apply when finding files.
2153 * @param dirFilter optional filter to apply when finding subdirectories.
2154 * If this parameter is {@code null}, subdirectories will not be included in the
2155 * search. Use TrueFileFilter.INSTANCE to match all directories.
2156 * @return an iterator of {@link File} for the matching files.
2157 * @see org.apache.commons.io.filefilter.FileFilterUtils
2158 * @see org.apache.commons.io.filefilter.NameFileFilter
2159 * @since 2.2
2160 */
2161 public static Iterator<File> iterateFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
2162 return listFilesAndDirs(directory, fileFilter, dirFilter).iterator();
2163 }
2164
2165 /**
2166 * Returns the last modification time in milliseconds via
2167 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
2168 * <p>
2169 * For the best precision, use {@link #lastModifiedFileTime(File)}.
2170 * </p>
2171 * <p>
2172 * Use this method to avoid issues with {@link File#lastModified()} like
2173 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
2174 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
2175 * </p>
2176 *
2177 * @param file The File to query.
2178 * @return See {@link java.nio.file.attribute.FileTime#toMillis()}.
2179 * @throws IOException if an I/O error occurs.
2180 * @since 2.9.0
2181 */
2182 public static long lastModified(final File file) throws IOException {
2183 // https://bugs.openjdk.java.net/browse/JDK-8177809
2184 // File.lastModified() is losing milliseconds (always ends in 000)
2185 // This bug is in OpenJDK 8 and 9, and fixed in 10.
2186 return lastModifiedFileTime(file).toMillis();
2187 }
2188
2189 /**
2190 * Returns the last modification {@link FileTime} via
2191 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
2192 * <p>
2193 * Use this method to avoid issues with {@link File#lastModified()} like
2194 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
2195 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
2196 * </p>
2197 *
2198 * @param file The File to query.
2199 * @return See {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
2200 * @throws IOException if an I/O error occurs.
2201 * @since 2.12.0
2202 */
2203 public static FileTime lastModifiedFileTime(final File file) throws IOException {
2204 // https://bugs.openjdk.java.net/browse/JDK-8177809
2205 // File.lastModified() is losing milliseconds (always ends in 000)
2206 // This bug is in OpenJDK 8 and 9, and fixed in 10.
2207 return Files.getLastModifiedTime(Objects.requireNonNull(file, PROTOCOL_FILE).toPath());
2208 }
2209
2210 /**
2211 * Returns the last modification time in milliseconds via
2212 * {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
2213 * <p>
2214 * For the best precision, use {@link #lastModifiedFileTime(File)}.
2215 * </p>
2216 * <p>
2217 * Use this method to avoid issues with {@link File#lastModified()} like
2218 * <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
2219 * losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
2220 * </p>
2221 *
2222 * @param file The File to query.
2223 * @return See {@link java.nio.file.attribute.FileTime#toMillis()}.
2224 * @throws UncheckedIOException if an I/O error occurs.
2225 * @since 2.9.0
2226 */
2227 public static long lastModifiedUnchecked(final File file) {
2228 // https://bugs.openjdk.java.net/browse/JDK-8177809
2229 // File.lastModified() is losing milliseconds (always ends in 000)
2230 // This bug is in OpenJDK 8 and 9, and fixed in 10.
2231 return Uncheck.apply(FileUtils::lastModified, file);
2232 }
2233
2234 /**
2235 * Returns an Iterator for the lines in a {@link File} using the default encoding for the VM.
2236 *
2237 * @param file the file to open for input, must not be {@code null}.
2238 * @return an Iterator of the lines in the file, never {@code null}.
2239 * @throws NullPointerException if file is {@code null}.
2240 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
2241 * other reason cannot be opened for reading.
2242 * @throws IOException if an I/O error occurs.
2243 * @see #lineIterator(File, String)
2244 * @since 1.3
2245 */
2246 public static LineIterator lineIterator(final File file) throws IOException {
2247 return lineIterator(file, null);
2248 }
2249
2250 /**
2251 * Returns an Iterator for the lines in a {@link File}.
2252 * <p>
2253 * This method opens an {@link InputStream} for the file.
2254 * When you have finished with the iterator you should close the stream
2255 * to free internal resources. This can be done by using a try-with-resources block or calling the
2256 * {@link LineIterator#close()} method.
2257 * </p>
2258 * <p>
2259 * The recommended usage pattern is:
2260 * </p>
2261 * <pre>
2262 * LineIterator it = FileUtils.lineIterator(file, StandardCharsets.UTF_8.name());
2263 * try {
2264 * while (it.hasNext()) {
2265 * String line = it.nextLine();
2266 * // do something with line
2267 * }
2268 * } finally {
2269 * LineIterator.closeQuietly(iterator);
2270 * }
2271 * </pre>
2272 * <p>
2273 * If an exception occurs during the creation of the iterator, the
2274 * underlying stream is closed.
2275 * </p>
2276 *
2277 * @param file the file to open for input, must not be {@code null}.
2278 * @param charsetName the name of the requested charset, {@code null} means platform default.
2279 * @return a LineIterator for lines in the file, never {@code null}; MUST be closed by the caller.
2280 * @throws NullPointerException if file is {@code null}.
2281 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
2282 * other reason cannot be opened for reading.
2283 * @throws IOException if an I/O error occurs.
2284 * @since 1.2
2285 */
2286 @SuppressWarnings("resource") // Caller closes the result LineIterator.
2287 public static LineIterator lineIterator(final File file, final String charsetName) throws IOException {
2288 InputStream inputStream = null;
2289 try {
2290 inputStream = Files.newInputStream(file.toPath());
2291 return IOUtils.lineIterator(inputStream, charsetName);
2292 } catch (final IOException | RuntimeException ex) {
2293 IOUtils.closeQuietly(inputStream, ex::addSuppressed);
2294 throw ex;
2295 }
2296 }
2297
2298 private static AccumulatorPathVisitor listAccumulate(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter,
2299 final FileVisitOption... options) throws IOException {
2300 final boolean isDirFilterSet = dirFilter != null;
2301 final FileEqualsFileFilter rootDirFilter = new FileEqualsFileFilter(directory);
2302 final PathFilter dirPathFilter = isDirFilterSet ? rootDirFilter.or(dirFilter) : rootDirFilter;
2303 // @formatter:off
2304 final AccumulatorPathVisitor visitor = AccumulatorPathVisitor.builder()
2305 .setPathCounters(Counters.noopPathCounters())
2306 .setFileFilter(fileFilter)
2307 .setDirectoryFilter(dirPathFilter)
2308 .setVisitFileFailedFunction((p, e) -> FileVisitResult.CONTINUE)
2309 .get();
2310 // @formatter:on
2311 final Set<FileVisitOption> optionSet = new HashSet<>();
2312 if (options != null) {
2313 Collections.addAll(optionSet, options);
2314 }
2315 Files.walkFileTree(directory.toPath(), optionSet, toMaxDepth(isDirFilterSet), visitor);
2316 return visitor;
2317 }
2318
2319 /**
2320 * Lists files in a directory, asserting that the supplied directory exists and is a directory.
2321 *
2322 * @param directory The directory to list.
2323 * @param fileFilter Optional file filter, may be null.
2324 * @return The files in the directory, never {@code null}.
2325 * @throws NullPointerException if the {@code directory} is {@code null}.
2326 * @throws IllegalArgumentException if the {@code directory} exists but is not a directory.
2327 * @throws IOException if an I/O error occurs per {@link File#listFiles()} and {@link File#listFiles(FileFilter)}.
2328 * @throws SecurityException If a security manager exists and its {@link SecurityManager#checkRead(String)} method denies read access to the
2329 * directory.
2330 */
2331 private static File[] listFiles(final File directory, final FileFilter fileFilter) throws IOException {
2332 requireDirectoryExists(directory, "directory");
2333 final File[] files = directory.listFiles(fileFilter);
2334 if (files == null) {
2335 // null if the directory does not denote a directory, or if an I/O error occurs.
2336 throw new IOException("Unknown I/O error listing contents of directory: " + directory);
2337 }
2338 return files;
2339 }
2340
2341 /**
2342 * Finds files within a given directory (and optionally its
2343 * subdirectories). All files found are filtered by an IOFileFilter.
2344 * <p>
2345 * If your search should recurse into subdirectories you can pass in
2346 * an IOFileFilter for directories. You don't need to bind a
2347 * DirectoryFileFilter (via logical AND) to this filter. This method does
2348 * that for you.
2349 * </p>
2350 * <p>
2351 * An example: If you want to search through all directories called
2352 * "temp" you pass in {@code FileFilterUtils.NameFileFilter("temp")}.
2353 * </p>
2354 * <p>
2355 * Another common usage of this method is find files in a directory
2356 * tree but ignoring the directories generated CVS. You can simply pass
2357 * in {@code FileFilterUtils.makeCVSAware(null)}.
2358 * </p>
2359 *
2360 * @param directory The directory to search.
2361 * @param fileFilter filter to apply when finding files. Must not be {@code null},
2362 * use {@link TrueFileFilter#INSTANCE} to match all files in selected directories.
2363 * @param dirFilter optional filter to apply when finding subdirectories.
2364 * If this parameter is {@code null}, subdirectories will not be included in the
2365 * search. Use {@link TrueFileFilter#INSTANCE} to match all directories.
2366 * @return a collection of {@link File} with the matching files.
2367 * @see org.apache.commons.io.filefilter.FileFilterUtils
2368 * @see org.apache.commons.io.filefilter.NameFileFilter
2369 */
2370 public static Collection<File> listFiles(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
2371 final AccumulatorPathVisitor visitor = Uncheck
2372 .apply(d -> listAccumulate(d, FileFileFilter.INSTANCE.and(fileFilter), dirFilter, FileVisitOption.FOLLOW_LINKS), directory);
2373 return toList(visitor.getFileList().stream().map(Path::toFile));
2374 }
2375
2376 /**
2377 * Lists Files in the given {@code directory}, adding each file to the given list.
2378 *
2379 * @param directory A File for an assumed directory, not null.
2380 * @param files The list to add found Files, not null.
2381 * @param recursive Whether or not to recurse into subdirectories.
2382 * @param filter How to filter files, not null.
2383 * @return The given list.
2384 */
2385 @SuppressWarnings("null")
2386 private static List<File> listFiles(final File directory, final List<File> files, final boolean recursive, final FilenameFilter filter) {
2387 final File[] listFiles = directory.listFiles();
2388 if (listFiles != null) {
2389 // Only allocate if you must.
2390 final List<File> dirs = recursive ? new ArrayList<>() : null;
2391 Arrays.stream(listFiles).forEach(f -> {
2392 if (recursive && f.isDirectory()) {
2393 dirs.add(f);
2394 } else if (f.isFile() && filter.accept(directory, f.getName())) {
2395 files.add(f);
2396 }
2397 });
2398 if (recursive) {
2399 dirs.forEach(d -> listFiles(d, files, true, filter));
2400 }
2401 }
2402 return files;
2403 }
2404
2405 /**
2406 * Lists files within a given directory (and optionally its subdirectories)
2407 * which match an array of extensions.
2408 *
2409 * @param directory The directory to search.
2410 * @param extensions an array of extensions, for example, <code>{"java", "xml"}</code>. If this
2411 * parameter is {@code null}, all files are returned.
2412 * @param recursive if true all subdirectories are searched as well.
2413 * @return a collection of {@link File} with the matching files.
2414 */
2415 public static Collection<File> listFiles(final File directory, final String[] extensions, final boolean recursive) {
2416 return listFiles(directory, new ArrayList<>(), recursive, extensions != null ? toSuffixFileFilter(extensions) : TrueFileFilter.INSTANCE);
2417 }
2418
2419 /**
2420 * Finds files within a given directory (and optionally its
2421 * subdirectories). All files found are filtered by an IOFileFilter.
2422 * <p>
2423 * The resulting collection includes the starting directory and
2424 * any subdirectories that match the directory filter.
2425 * </p>
2426 *
2427 * @param directory The directory to search.
2428 * @param fileFilter filter to apply when finding files.
2429 * @param dirFilter optional filter to apply when finding subdirectories.
2430 * If this parameter is {@code null}, subdirectories will not be included in the
2431 * search. Use TrueFileFilter.INSTANCE to match all directories.
2432 * @return a collection of {@link File} with the matching files.
2433 * @see org.apache.commons.io.FileUtils#listFiles
2434 * @see org.apache.commons.io.filefilter.FileFilterUtils
2435 * @see org.apache.commons.io.filefilter.NameFileFilter
2436 * @since 2.2
2437 */
2438 public static Collection<File> listFilesAndDirs(final File directory, final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
2439 final AccumulatorPathVisitor visitor = Uncheck.apply(d -> listAccumulate(d, fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS),
2440 directory);
2441 final List<Path> list = visitor.getFileList();
2442 list.addAll(visitor.getDirList());
2443 return toList(list.stream().map(Path::toFile));
2444 }
2445
2446 /**
2447 * Calls {@link File#mkdirs()} and throws an {@link IOException} on failure.
2448 * <p>
2449 * Creates all directories for a File object, including any necessary but non-existent parent directories. If the {@code directory} already exists or is
2450 * null, nothing happens.
2451 * </p>
2452 *
2453 * @param directory the receiver for {@code mkdirs()}. If the {@code directory} already exists or is null, nothing happens.
2454 * @return the given directory.
2455 * @throws IOException if the directory was not created along with all its parent directories.
2456 * @throws IOException if the given file object is not a directory.
2457 * @throws SecurityException See {@link File#mkdirs()}.
2458 * @see File#mkdirs()
2459 */
2460 private static File mkdirs(final File directory) throws IOException {
2461 if (directory != null && !directory.mkdirs() && !directory.isDirectory()) {
2462 throw new IOException("Cannot create directory '" + directory + "'.");
2463 }
2464 return directory;
2465 }
2466
2467 /**
2468 * Moves a directory.
2469 * <p>
2470 * When the destination directory is on another file system, do a "copy and delete".
2471 * </p>
2472 *
2473 * @param srcDir the directory to be moved.
2474 * @param destDir the destination directory.
2475 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2476 * @throws IllegalArgumentException if {@code srcDir} exists but is not a directory.
2477 * @throws FileNotFoundException if the source does not exist.
2478 * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
2479 * @since 1.4
2480 */
2481 public static void moveDirectory(final File srcDir, final File destDir) throws IOException {
2482 Objects.requireNonNull(destDir, "destination");
2483 requireDirectoryExists(srcDir, "srcDir");
2484 requireAbsent(destDir, "destDir");
2485 if (!srcDir.renameTo(destDir)) {
2486 if (destDir.getCanonicalPath().startsWith(srcDir.getCanonicalPath() + File.separator)) {
2487 throw new IOException("Cannot move directory: " + srcDir + " to a subdirectory of itself: " + destDir);
2488 }
2489 copyDirectory(srcDir, destDir);
2490 deleteDirectory(srcDir);
2491 if (srcDir.exists()) {
2492 throw new IOException("Failed to delete original directory '" + srcDir +
2493 "' after copy to '" + destDir + "'");
2494 }
2495 }
2496 }
2497
2498 /**
2499 * Moves a directory to another directory.
2500 * <p>
2501 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
2502 * </p>
2503 *
2504 * @param source the directory to be moved.
2505 * @param destDir the destination file.
2506 * @param createDestDir If {@code true} create the destination directory, otherwise if {@code false} throw an
2507 * IOException.
2508 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2509 * @throws IllegalArgumentException if the source or destination is invalid.
2510 * @throws FileNotFoundException if the source does not exist.
2511 * @throws IOException if the directory was not created along with all its parent directories, if enabled.
2512 * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
2513 * @throws SecurityException See {@link File#mkdirs()}.
2514 * @since 1.4
2515 */
2516 public static void moveDirectoryToDirectory(final File source, final File destDir, final boolean createDestDir) throws IOException {
2517 validateMoveParameters(source, destDir);
2518 if (!destDir.isDirectory()) {
2519 if (destDir.exists()) {
2520 throw new IOException("Destination '" + destDir + "' is not a directory");
2521 }
2522 if (!createDestDir) {
2523 throw new FileNotFoundException("Destination directory '" + destDir + "' does not exist [createDestDir=" + false + "]");
2524 }
2525 mkdirs(destDir);
2526 }
2527 moveDirectory(source, new File(destDir, source.getName()));
2528 }
2529
2530 /**
2531 * Moves a file preserving attributes.
2532 * <p>
2533 * Shorthand for {@code moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES)}.
2534 * </p>
2535 * <p>
2536 * When the destination file is on another file system, do a "copy and delete".
2537 * </p>
2538 *
2539 * @param srcFile the file to be moved.
2540 * @param destFile the destination file.
2541 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2542 * @throws FileExistsException if the destination file exists.
2543 * @throws FileNotFoundException if the source file does not exist.
2544 * @throws IllegalArgumentException if {@code srcFile} is a directory.
2545 * @throws IOException if an error occurs.
2546 * @since 1.4
2547 */
2548 public static void moveFile(final File srcFile, final File destFile) throws IOException {
2549 moveFile(srcFile, destFile, StandardCopyOption.COPY_ATTRIBUTES);
2550 }
2551
2552 /**
2553 * Moves a file.
2554 * <p>
2555 * When the destination file is on another file system, do a "copy and delete".
2556 * </p>
2557 *
2558 * @param srcFile the file to be moved.
2559 * @param destFile the destination file.
2560 * @param copyOptions Copy options.
2561 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2562 * @throws FileExistsException if the destination file exists.
2563 * @throws FileNotFoundException if the source file does not exist.
2564 * @throws IllegalArgumentException if {@code srcFile} is a directory.
2565 * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
2566 * @since 2.9.0
2567 */
2568 public static void moveFile(final File srcFile, final File destFile, final CopyOption... copyOptions) throws IOException {
2569 Objects.requireNonNull(destFile, "destFile");
2570 checkFileExists(srcFile, "srcFile");
2571 requireAbsent(destFile, "destFile");
2572 final boolean rename = srcFile.renameTo(destFile);
2573 if (!rename) {
2574 // Don't interfere with file date on move, handled by StandardCopyOption.COPY_ATTRIBUTES
2575 copyFile(srcFile, destFile, false, copyOptions);
2576 if (!srcFile.delete()) {
2577 deleteQuietly(destFile);
2578 throw new IOException("Failed to delete original file '" + srcFile + "' after copy to '" + destFile + "'");
2579 }
2580 }
2581 }
2582
2583 /**
2584 * Moves a file into a directory.
2585 * <p>
2586 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
2587 * </p>
2588 *
2589 * @param srcFile the file to be moved.
2590 * @param destDir the directory to move the file into.
2591 * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an
2592 * IOException if the destination directory does not already exist.
2593 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2594 * @throws FileExistsException if the destination file exists.
2595 * @throws FileNotFoundException if the source file does not exist.
2596 * @throws IOException if source or destination is invalid.
2597 * @throws IOException if the directory was not created along with all its parent directories, if enabled.
2598 * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
2599 * @throws SecurityException See {@link File#mkdirs()}.
2600 * @throws IllegalArgumentException if {@code destDir} exists but is not a directory.
2601 * @since 1.4
2602 */
2603 public static void moveFileToDirectory(final File srcFile, final File destDir, final boolean createDestDir) throws IOException {
2604 validateMoveParameters(srcFile, destDir);
2605 if (!destDir.exists() && createDestDir) {
2606 mkdirs(destDir);
2607 }
2608 requireDirectoryExists(destDir, "destDir");
2609 moveFile(srcFile, new File(destDir, srcFile.getName()));
2610 }
2611
2612 /**
2613 * Moves a file or directory into a destination directory.
2614 * <p>
2615 * If {@code createDestDir} is true, creates all destination parent directories, including any necessary but non-existent parent directories.
2616 * </p>
2617 * <p>
2618 * When the destination is on another file system, do a "copy and delete".
2619 * </p>
2620 *
2621 * @param src the file or directory to be moved.
2622 * @param destDir the destination directory.
2623 * @param createDestDir if {@code true} create the destination directory. If {@code false} throw an
2624 * IOException if the destination directory does not already exist.
2625 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
2626 * @throws FileExistsException if the directory or file exists in the destination directory.
2627 * @throws FileNotFoundException if the source file does not exist.
2628 * @throws IOException if source or destination is invalid.
2629 * @throws IOException if an error occurs or setting the last-modified time didn't succeed.
2630 * @since 1.4
2631 */
2632 public static void moveToDirectory(final File src, final File destDir, final boolean createDestDir) throws IOException {
2633 validateMoveParameters(src, destDir);
2634 if (src.isDirectory()) {
2635 moveDirectoryToDirectory(src, destDir, createDestDir);
2636 } else {
2637 moveFileToDirectory(src, destDir, createDestDir);
2638 }
2639 }
2640
2641 /**
2642 * Creates a new OutputStream by opening or creating a file, returning an output stream that may be used to write bytes
2643 * to the file.
2644 *
2645 * @param append Whether or not to append.
2646 * @param file the File.
2647 * @return a new OutputStream.
2648 * @throws IOException if an I/O error occurs.
2649 * @see PathUtils#newOutputStream(Path, boolean)
2650 * @since 2.12.0
2651 */
2652 public static OutputStream newOutputStream(final File file, final boolean append) throws IOException {
2653 return PathUtils.newOutputStream(Objects.requireNonNull(file, PROTOCOL_FILE).toPath(), append);
2654 }
2655
2656 /**
2657 * Opens a {@link FileInputStream} for the specified file, providing better error messages than simply calling
2658 * {@code new FileInputStream(file)}.
2659 * <p>
2660 * At the end of the method either the stream will be successfully opened, or an exception will have been thrown.
2661 * </p>
2662 * <p>
2663 * An exception is thrown if the file does not exist. An exception is thrown if the file object exists but is a
2664 * directory. An exception is thrown if the file exists but cannot be read.
2665 * </p>
2666 *
2667 * @param file the file to open for input, must not be {@code null}.
2668 * @return a new {@link FileInputStream} for the specified file.
2669 * @throws NullPointerException if file is {@code null}.
2670 * @throws FileNotFoundException if the file does not exist, is a directory rather than a regular file, or for some
2671 * other reason cannot be opened for reading.
2672 * @throws IOException See FileNotFoundException above, FileNotFoundException is a subclass of IOException.
2673 * @since 1.3
2674 */
2675 public static FileInputStream openInputStream(final File file) throws IOException {
2676 Objects.requireNonNull(file, PROTOCOL_FILE);
2677 return new FileInputStream(file);
2678 }
2679
2680 /**
2681 * Opens a {@link FileOutputStream} for the specified file, checking and
2682 * creating the parent directory if it does not exist.
2683 * <p>
2684 * At the end of the method either the stream will be successfully opened,
2685 * or an exception will have been thrown.
2686 * </p>
2687 * <p>
2688 * The parent directory will be created if it does not exist.
2689 * The file will be created if it does not exist.
2690 * An exception is thrown if the file object exists but is a directory.
2691 * An exception is thrown if the file exists but cannot be written to.
2692 * An exception is thrown if the parent directory cannot be created.
2693 * </p>
2694 *
2695 * @param file the file to open for output, must not be {@code null}.
2696 * @return a new {@link FileOutputStream} for the specified file
2697 * @throws NullPointerException if the file object is {@code null}.
2698 * @throws IllegalArgumentException if the file object is a directory
2699 * @throws IllegalArgumentException if the file is not writable.
2700 * @throws IOException if the directories could not be created.
2701 * @since 1.3
2702 */
2703 public static FileOutputStream openOutputStream(final File file) throws IOException {
2704 return openOutputStream(file, false);
2705 }
2706
2707 /**
2708 * Opens a {@link FileOutputStream} for the specified file, checking and
2709 * creating the parent directory if it does not exist.
2710 * <p>
2711 * At the end of the method either the stream will be successfully opened,
2712 * or an exception will have been thrown.
2713 * </p>
2714 * <p>
2715 * The parent directory will be created if it does not exist.
2716 * The file will be created if it does not exist.
2717 * An exception is thrown if the file object exists but is a directory.
2718 * An exception is thrown if the file exists but cannot be written to.
2719 * An exception is thrown if the parent directory cannot be created.
2720 * </p>
2721 *
2722 * @param file the file to open for output, must not be {@code null}.
2723 * @param append if {@code true}, then bytes will be added to the
2724 * end of the file rather than overwriting.
2725 * @return a new {@link FileOutputStream} for the specified file.
2726 * @throws NullPointerException if the file object is {@code null}.
2727 * @throws IllegalArgumentException if the file object is a directory.
2728 * @throws IOException if the directories could not be created, or the file is not writable.
2729 * @since 2.1
2730 */
2731 public static FileOutputStream openOutputStream(final File file, final boolean append) throws IOException {
2732 Objects.requireNonNull(file, PROTOCOL_FILE);
2733 if (file.exists()) {
2734 checkIsFile(file, PROTOCOL_FILE);
2735 } else {
2736 createParentDirectories(file);
2737 }
2738 return new FileOutputStream(file, append);
2739 }
2740
2741 /**
2742 * Reads the contents of a file into a byte array.
2743 * The file is always closed.
2744 *
2745 * @param file the file to read, must not be {@code null}.
2746 * @return the file contents, never {@code null}.
2747 * @throws NullPointerException if file is {@code null}.
2748 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
2749 * regular file, or for some other reason why the file cannot be opened for reading.
2750 * @since 1.1
2751 */
2752 public static byte[] readFileToByteArray(final File file) throws IOException {
2753 Objects.requireNonNull(file, PROTOCOL_FILE);
2754 return Files.readAllBytes(file.toPath());
2755 }
2756
2757 /**
2758 * Reads the contents of a file into a String using the virtual machine's {@linkplain Charset#defaultCharset() default charset}. The
2759 * file is always closed.
2760 *
2761 * @param file the file to read, must not be {@code null}.
2762 * @return the file contents, never {@code null}.
2763 * @throws NullPointerException if file is {@code null}.
2764 * @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
2765 * reason why the file cannot be opened for reading.
2766 * @since 1.3.1
2767 * @deprecated Use {@link #readFileToString(File, Charset)} instead (and specify the appropriate encoding).
2768 */
2769 @Deprecated
2770 public static String readFileToString(final File file) throws IOException {
2771 return readFileToString(file, Charset.defaultCharset());
2772 }
2773
2774 /**
2775 * Reads the contents of a file into a String.
2776 * The file is always closed.
2777 *
2778 * @param file the file to read, must not be {@code null}.
2779 * @param charsetName the name of the requested charset, {@code null} means platform default.
2780 * @return the file contents, never {@code null}.
2781 * @throws NullPointerException if file is {@code null}.
2782 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
2783 * regular file, or for some other reason why the file cannot be opened for reading.
2784 * @since 2.3
2785 */
2786 public static String readFileToString(final File file, final Charset charsetName) throws IOException {
2787 return IOUtils.toString(() -> Files.newInputStream(file.toPath()), Charsets.toCharset(charsetName));
2788 }
2789
2790 /**
2791 * Reads the contents of a file into a String. The file is always closed.
2792 *
2793 * @param file the file to read, must not be {@code null}.
2794 * @param charsetName the name of the requested charset, {@code null} means platform default.
2795 * @return the file contents, never {@code null}.
2796 * @throws NullPointerException if file is {@code null}.
2797 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
2798 * regular file, or for some other reason why the file cannot be opened for reading.
2799 * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable.
2800 * @since 2.3
2801 */
2802 public static String readFileToString(final File file, final String charsetName) throws IOException {
2803 return readFileToString(file, Charsets.toCharset(charsetName));
2804 }
2805
2806 /**
2807 * Reads the contents of a file line by line to a List of Strings using the virtual machine's {@linkplain Charset#defaultCharset() default charset}.
2808 * The file is always closed.
2809 *
2810 * @param file the file to read, must not be {@code null}.
2811 * @return the list of Strings representing each line in the file, never {@code null}.
2812 * @throws NullPointerException if file is {@code null}.
2813 * @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
2814 * reason why the file cannot be opened for reading.
2815 * @since 1.3
2816 * @deprecated Use {@link #readLines(File, Charset)} instead (and specify the appropriate encoding).
2817 */
2818 @Deprecated
2819 public static List<String> readLines(final File file) throws IOException {
2820 return readLines(file, Charset.defaultCharset());
2821 }
2822
2823 /**
2824 * Reads the contents of a file line by line to a List of Strings.
2825 * The file is always closed.
2826 *
2827 * @param file the file to read, must not be {@code null}.
2828 * @param charset the charset to use, {@code null} means platform default.
2829 * @return the list of Strings representing each line in the file, never {@code null}.
2830 * @throws NullPointerException if file is {@code null}.
2831 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
2832 * regular file, or for some other reason why the file cannot be opened for reading.
2833 * @since 2.3
2834 */
2835 public static List<String> readLines(final File file, final Charset charset) throws IOException {
2836 return Files.readAllLines(file.toPath(), Charsets.toCharset(charset));
2837 }
2838
2839 /**
2840 * Reads the contents of a file line by line to a List of Strings. The file is always closed.
2841 *
2842 * @param file the file to read, must not be {@code null}.
2843 * @param charsetName the name of the requested charset, {@code null} means platform default.
2844 * @return the list of Strings representing each line in the file, never {@code null}.
2845 * @throws NullPointerException if file is {@code null}.
2846 * @throws IOException if an I/O error occurs, including when the file does not exist, is a directory rather than a
2847 * regular file, or for some other reason why the file cannot be opened for reading.
2848 * @throws java.nio.charset.UnsupportedCharsetException if the named charset is unavailable.
2849 * @since 1.1
2850 */
2851 public static List<String> readLines(final File file, final String charsetName) throws IOException {
2852 return readLines(file, Charsets.toCharset(charsetName));
2853 }
2854
2855 private static void requireAbsent(final File file, final String name) throws FileExistsException {
2856 if (file.exists()) {
2857 throw new FileExistsException(String.format("File element in parameter '%s' already exists: '%s'", name, file));
2858 }
2859 }
2860
2861 /**
2862 * Throws IllegalArgumentException if the given files' canonical representations are equal.
2863 *
2864 * @param file1 The first file to compare.
2865 * @param file2 The second file to compare.
2866 * @throws IOException if an I/O error occurs.
2867 * @throws IllegalArgumentException if the given files' canonical representations are equal.
2868 */
2869 private static void requireCanonicalPathsNotEquals(final File file1, final File file2) throws IOException {
2870 final String canonicalPath = file1.getCanonicalPath();
2871 if (canonicalPath.equals(file2.getCanonicalPath())) {
2872 throw new IllegalArgumentException(String
2873 .format("File canonical paths are equal: '%s' (file1='%s', file2='%s')", canonicalPath, file1, file2));
2874 }
2875 }
2876
2877 /**
2878 * Requires that the given {@link File} exists and is a directory.
2879 *
2880 * @param directory The {@link File} to check.
2881 * @param name The parameter name to use in the exception message in case of null input or if the file is not a directory.
2882 * @throws NullPointerException if the given {@link File} is {@code null}.
2883 * @throws FileNotFoundException if the given {@link File} does not exist.
2884 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
2885 */
2886 private static void requireDirectoryExists(final File directory, final String name) throws FileNotFoundException {
2887 Objects.requireNonNull(directory, name);
2888 if (!directory.isDirectory()) {
2889 if (directory.exists()) {
2890 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'");
2891 }
2892 throw new FileNotFoundException("Directory '" + directory + "' does not exist.");
2893 }
2894 }
2895
2896 /**
2897 * Requires that the given {@link File} is a directory if it exists.
2898 *
2899 * @param directory The {@link File} to check.
2900 * @param name The parameter name to use in the exception message in case of null input.
2901 * @throws NullPointerException if the given {@link File} is {@code null}.
2902 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
2903 */
2904 private static void requireDirectoryIfExists(final File directory, final String name) {
2905 Objects.requireNonNull(directory, name);
2906 if (directory.exists() && !directory.isDirectory()) {
2907 throw new IllegalArgumentException("Parameter '" + name + "' is not a directory: '" + directory + "'");
2908 }
2909 }
2910
2911 /**
2912 * Sets file lastModifiedTime, lastAccessTime and creationTime to match source file
2913 *
2914 * @param sourceFile The source file to query.
2915 * @param targetFile The target file or directory to set.
2916 * @return {@code true} if and only if the operation succeeded; {@code false} otherwise.
2917 * @throws NullPointerException if sourceFile is {@code null}.
2918 * @throws NullPointerException if targetFile is {@code null}.
2919 */
2920 private static boolean setTimes(final File sourceFile, final File targetFile) {
2921 Objects.requireNonNull(sourceFile, "sourceFile");
2922 Objects.requireNonNull(targetFile, "targetFile");
2923 try {
2924 // Set creation, modified, last accessed to match source file
2925 final BasicFileAttributes srcAttr = Files.readAttributes(sourceFile.toPath(), BasicFileAttributes.class);
2926 final BasicFileAttributeView destAttrView = Files.getFileAttributeView(targetFile.toPath(), BasicFileAttributeView.class);
2927 // null guards are not needed; BasicFileAttributes.setTimes(...) is null safe
2928 destAttrView.setTimes(srcAttr.lastModifiedTime(), srcAttr.lastAccessTime(), srcAttr.creationTime());
2929 return true;
2930 } catch (final IOException ignored) {
2931 // Fallback: Only set modified time to match source file
2932 return targetFile.setLastModified(sourceFile.lastModified());
2933 }
2934 // TODO: (Help!) Determine historically why setLastModified(File, File) needed PathUtils.setLastModifiedTime() if
2935 // sourceFile.isFile() was true, but needed setLastModifiedTime(File, long) if sourceFile.isFile() was false
2936 }
2937
2938 /**
2939 * Returns the size of the specified file or directory. If the provided
2940 * {@link File} is a regular file, then the file's length is returned.
2941 * If the argument is a directory, then the size of the directory is
2942 * calculated recursively. If a directory or subdirectory is security
2943 * restricted, its size will not be included.
2944 * <p>
2945 * Note that overflow is not detected, and the return value may be negative if
2946 * overflow occurs. See {@link #sizeOfAsBigInteger(File)} for an alternative
2947 * method that does not overflow.
2948 * </p>
2949 *
2950 * @param file the regular file or directory to return the size
2951 * of (must not be {@code null}).
2952 *
2953 * @return the length of the file, or recursive size of the directory,
2954 * provided (in bytes).
2955 *
2956 * @throws NullPointerException if the file is {@code null}.
2957 * @throws IllegalArgumentException if the file does not exist.
2958 * @throws UncheckedIOException if an IO error occurs.
2959 * @since 2.0
2960 */
2961 public static long sizeOf(final File file) {
2962 return Uncheck.getAsLong(() -> PathUtils.sizeOf(file.toPath()));
2963 }
2964
2965 /**
2966 * Returns the size of the specified file or directory. If the provided
2967 * {@link File} is a regular file, then the file's length is returned.
2968 * If the argument is a directory, then the size of the directory is
2969 * calculated recursively. If a directory or subdirectory is security
2970 * restricted, its size will not be included.
2971 *
2972 * @param file the regular file or directory to return the size
2973 * of (must not be {@code null}).
2974 *
2975 * @return the length of the file, or recursive size of the directory,
2976 * provided (in bytes).
2977 *
2978 * @throws NullPointerException if the file is {@code null}.
2979 * @throws IllegalArgumentException if the file does not exist.
2980 * @throws UncheckedIOException if an IO error occurs.
2981 * @since 2.4
2982 */
2983 public static BigInteger sizeOfAsBigInteger(final File file) {
2984 return Uncheck.get(() -> PathUtils.sizeOfAsBigInteger(file.toPath()));
2985 }
2986
2987 /**
2988 * Counts the size of a directory recursively (sum of the length of all files).
2989 * <p>
2990 * Note that overflow is not detected, and the return value may be negative if
2991 * overflow occurs. See {@link #sizeOfDirectoryAsBigInteger(File)} for an alternative
2992 * method that does not overflow.
2993 * </p>
2994 *
2995 * @param directory directory to inspect, must not be {@code null}.
2996 * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total
2997 * is greater than {@link Long#MAX_VALUE}.
2998 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
2999 * @throws NullPointerException if the directory is {@code null}.
3000 * @throws UncheckedIOException if an IO error occurs.
3001 */
3002 public static long sizeOfDirectory(final File directory) {
3003 try {
3004 requireDirectoryExists(directory, "directory");
3005 } catch (final FileNotFoundException e) {
3006 throw new UncheckedIOException(e);
3007 }
3008 return Uncheck.getAsLong(() -> PathUtils.sizeOfDirectory(directory.toPath()));
3009 }
3010
3011 /**
3012 * Counts the size of a directory recursively (sum of the length of all files).
3013 *
3014 * @param directory directory to inspect, must not be {@code null}.
3015 * @return size of directory in bytes, 0 if directory is security restricted.
3016 * @throws IllegalArgumentException if the given {@link File} exists but is not a directory.
3017 * @throws NullPointerException if the directory is {@code null}.
3018 * @throws UncheckedIOException if an IO error occurs.
3019 * @since 2.4
3020 */
3021 public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) {
3022 try {
3023 requireDirectoryExists(directory, "directory");
3024 } catch (final FileNotFoundException e) {
3025 throw new UncheckedIOException(e);
3026 }
3027 return Uncheck.get(() -> PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath()));
3028 }
3029
3030 /**
3031 * Streams over the files in a given directory (and optionally its subdirectories) which match an array of extensions.
3032 * <p>
3033 * The returned {@link Stream} may wrap one or more {@link DirectoryStream}s. When you require timely disposal of file system resources, use a
3034 * {@code try}-with-resources block to ensure invocation of the stream's {@link Stream#close()} method after the stream operations are completed. Calling a
3035 * closed stream causes a {@link IllegalStateException}.
3036 * </p>
3037 *
3038 * @param directory The directory to search.
3039 * @param recursive if true all subdirectories are searched as well.
3040 * @param extensions an array of extensions, for example, <code>{"java", "xml"}</code>. If this parameter is {@code null}, all files are returned.
3041 * @return a Stream of {@link File} for matching files.
3042 * @throws IOException if an I/O error is thrown when accessing the starting file.
3043 * @since 2.9.0
3044 */
3045 public static Stream<File> streamFiles(final File directory, final boolean recursive, final String... extensions) throws IOException {
3046 // @formatter:off
3047 final IOFileFilter filter = extensions == null
3048 ? FileFileFilter.INSTANCE
3049 : FileFileFilter.INSTANCE.and(toSuffixFileFilter(extensions));
3050 // @formatter:on
3051 return PathUtils.walk(directory.toPath(), filter, toMaxDepth(recursive), false, FileVisitOption.FOLLOW_LINKS).map(Path::toFile);
3052 }
3053
3054 /**
3055 * Converts from a {@link URL} to a {@link File}.
3056 * <p>
3057 * 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
3058 * to characters. Additionally, malformed percent-encoded octets are handled leniently by passing them through literally.
3059 * </p>
3060 *
3061 * @param url the file URL to convert, {@code null} returns {@code null}.
3062 * @return the equivalent {@link File} object, or {@code null} if the URL's protocol is not {@code file}.
3063 */
3064 public static File toFile(final URL url) {
3065 if (url == null || !isFileProtocol(url)) {
3066 return null;
3067 }
3068 final String fileName = url.getFile().replace('/', File.separatorChar);
3069 return new File(decodeUrl(fileName));
3070 }
3071
3072 /**
3073 * Converts each of an array of {@link URL} to a {@link File}.
3074 * <p>
3075 * 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
3076 * array contains {@code null} at the same index.
3077 * </p>
3078 * <p>
3079 * 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}.
3080 * </p>
3081 *
3082 * @param urls the file URLs to convert, {@code null} returns empty array.
3083 * @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.
3084 * @throws IllegalArgumentException if any file is not a URL file.
3085 * @throws IllegalArgumentException if any file is incorrectly encoded.
3086 * @since 1.1
3087 */
3088 public static File[] toFiles(final URL... urls) {
3089 if (IOUtils.length(urls) == 0) {
3090 return EMPTY_FILE_ARRAY;
3091 }
3092 final File[] files = new File[urls.length];
3093 for (int i = 0; i < urls.length; i++) {
3094 final URL url = urls[i];
3095 if (url != null) {
3096 if (!isFileProtocol(url)) {
3097 throw new IllegalArgumentException("Can only convert file URL to a File: " + url);
3098 }
3099 files[i] = toFile(url);
3100 }
3101 }
3102 return files;
3103 }
3104
3105 /**
3106 * Consumes all of the given stream.
3107 * <p>
3108 * When called from a FileTreeWalker, the walker <em>closes</em> the stream because {@link FileTreeWalker#next()} calls {@code top.stream().close()}.
3109 * </p>
3110 *
3111 * @param stream The stream to consume.
3112 * @return a new List.
3113 */
3114 private static List<File> toList(final Stream<File> stream) {
3115 return stream.collect(Collectors.toList());
3116 }
3117
3118 /**
3119 * Converts whether or not to recurse into a recursion max depth.
3120 *
3121 * @param recursive whether or not to recurse.
3122 * @return the recursion depth.
3123 */
3124 private static int toMaxDepth(final boolean recursive) {
3125 return recursive ? Integer.MAX_VALUE : 1;
3126 }
3127
3128 /**
3129 * Converts an array of file extensions to suffixes.
3130 *
3131 * @param extensions an array of extensions, for example: {@code ["java", "xml"]}.
3132 * @return an array of suffixes, for example: {@code [".java", ".xml"]}.
3133 * @throws NullPointerException if the parameter is null.
3134 */
3135 private static String[] toSuffixes(final String... extensions) {
3136 return Stream.of(Objects.requireNonNull(extensions, "extensions")).map(s -> s.charAt(0) == '.' ? s : "." + s).toArray(String[]::new);
3137 }
3138
3139 private static SuffixFileFilter toSuffixFileFilter(final String... extensions) {
3140 return new SuffixFileFilter(toSuffixes(extensions));
3141 }
3142
3143 /**
3144 * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just
3145 * updates the file's modified time. This method throws an IOException if the last modified date
3146 * of the file cannot be set. It creates parent directories if they do not exist.
3147 *
3148 * @param file the File to touch.
3149 * @throws NullPointerException if the parameter is {@code null}.
3150 * @throws IOException if setting the last-modified time failed or an I/O problem occurs.
3151 */
3152 public static void touch(final File file) throws IOException {
3153 PathUtils.touch(Objects.requireNonNull(file, PROTOCOL_FILE).toPath());
3154 }
3155
3156 /**
3157 * Converts each element of an array of {@link File} to a {@link URL}.
3158 * <p>
3159 * Returns an array of the same size as the input.
3160 * </p>
3161 *
3162 * @param files the files to convert, must not be {@code null}.
3163 * @return an array of URLs matching the input.
3164 * @throws IOException if a file cannot be converted.
3165 * @throws NullPointerException if any argument is null.
3166 */
3167 public static URL[] toURLs(final File... files) throws IOException {
3168 Objects.requireNonNull(files, "files");
3169 final URL[] urls = new URL[files.length];
3170 for (int i = 0; i < urls.length; i++) {
3171 urls[i] = files[i].toURI().toURL();
3172 }
3173 return urls;
3174 }
3175
3176 /**
3177 * Validates the given arguments.
3178 * <ul>
3179 * <li>Throws {@link NullPointerException} if {@code source} is null</li>
3180 * <li>Throws {@link NullPointerException} if {@code destination} is null</li>
3181 * <li>Throws {@link FileNotFoundException} if {@code source} does not exist</li>
3182 * </ul>
3183 *
3184 * @param source the file or directory to be moved.
3185 * @param destination the destination file or directory.
3186 * @throws NullPointerException if any of the given {@link File}s are {@code null}.
3187 * @throws FileNotFoundException if the source file does not exist.
3188 */
3189 private static void validateMoveParameters(final File source, final File destination) throws FileNotFoundException {
3190 Objects.requireNonNull(source, "source");
3191 Objects.requireNonNull(destination, "destination");
3192 if (!source.exists()) {
3193 throw new FileNotFoundException("Source '" + source + "' does not exist");
3194 }
3195 }
3196
3197 /**
3198 * Waits for the file system to detect a file's presence, with a timeout.
3199 * <p>
3200 * This method repeatedly tests {@link Files#exists(Path, LinkOption...)} until it returns
3201 * true up to the maximum time specified in seconds.
3202 * </p>
3203 *
3204 * @param file the file to check, must not be {@code null}.
3205 * @param seconds the maximum time in seconds to wait.
3206 * @return true if file exists.
3207 * @throws NullPointerException if the file is {@code null}.
3208 */
3209 public static boolean waitFor(final File file, final int seconds) {
3210 Objects.requireNonNull(file, PROTOCOL_FILE);
3211 return PathUtils.waitFor(file.toPath(), Duration.ofSeconds(seconds), PathUtils.EMPTY_LINK_OPTION_ARRAY);
3212 }
3213
3214 /**
3215 * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@linkplain Charset#defaultCharset() default charset}.
3216 *
3217 * @param file the file to write.
3218 * @param data the content to write to the file.
3219 * @throws IOException in case of an I/O error.
3220 * @since 2.0
3221 * @deprecated Use {@link #write(File, CharSequence, Charset)} instead (and specify the appropriate encoding).
3222 */
3223 @Deprecated
3224 public static void write(final File file, final CharSequence data) throws IOException {
3225 write(file, data, Charset.defaultCharset(), false);
3226 }
3227
3228 /**
3229 * Writes a CharSequence to a file creating the file if it does not exist using the virtual machine's {@linkplain Charset#defaultCharset() default charset}.
3230 *
3231 * @param file the file to write.
3232 * @param data the content to write to the file.
3233 * @param append if {@code true}, then the data will be added to the end of the file rather than overwriting.
3234 * @throws IOException in case of an I/O error.
3235 * @since 2.1
3236 * @deprecated Use {@link #write(File, CharSequence, Charset, boolean)} instead (and specify the appropriate encoding).
3237 */
3238 @Deprecated
3239 public static void write(final File file, final CharSequence data, final boolean append) throws IOException {
3240 write(file, data, Charset.defaultCharset(), append);
3241 }
3242
3243 /**
3244 * Writes a CharSequence to a file creating the file if it does not exist.
3245 *
3246 * @param file the file to write.
3247 * @param data the content to write to the file.
3248 * @param charset the name of the requested charset, {@code null} means platform default.
3249 * @throws IOException in case of an I/O error.
3250 * @since 2.3
3251 */
3252 public static void write(final File file, final CharSequence data, final Charset charset) throws IOException {
3253 write(file, data, charset, false);
3254 }
3255
3256 /**
3257 * Writes a CharSequence to a file creating the file if it does not exist.
3258 *
3259 * @param file the file to write.
3260 * @param data the content to write to the file.
3261 * @param charset the charset to use, {@code null} means platform default.
3262 * @param append if {@code true}, then the data will be added to the.
3263 * end of the file rather than overwriting.
3264 * @throws IOException in case of an I/O error.
3265 * @since 2.3
3266 */
3267 public static void write(final File file, final CharSequence data, final Charset charset, final boolean append) throws IOException {
3268 writeStringToFile(file, Objects.toString(data, null), charset, append);
3269 }
3270
3271 /**
3272 * Writes a CharSequence to a file creating the file if it does not exist.
3273 *
3274 * @param file the file to write
3275 * @param data the content to write to the file
3276 * @param charsetName the name of the requested charset, {@code null} means platform default
3277 * @throws IOException in case of an I/O error
3278 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3279 * @since 2.0
3280 */
3281 public static void write(final File file, final CharSequence data, final String charsetName) throws IOException {
3282 write(file, data, charsetName, false);
3283 }
3284
3285 /**
3286 * Writes a CharSequence to a file creating the file if it does not exist.
3287 *
3288 * @param file the file to write
3289 * @param data the content to write to the file
3290 * @param charsetName the name of the requested charset, {@code null} means platform default
3291 * @param append if {@code true}, then the data will be added to the
3292 * end of the file rather than overwriting
3293 * @throws IOException in case of an I/O error
3294 * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
3295 * @since 2.1
3296 */
3297 public static void write(final File file, final CharSequence data, final String charsetName, final boolean append) throws IOException {
3298 write(file, data, Charsets.toCharset(charsetName), append);
3299 }
3300
3301 // Must be called with a directory
3302
3303 /**
3304 * Writes a byte array to a file creating the file if it does not exist.
3305 * The parent directories of the file will be created if they do not exist.
3306 *
3307 * @param file the file to write to
3308 * @param data the content to write to the file
3309 * @throws IOException in case of an I/O error
3310 * @since 1.1
3311 */
3312 public static void writeByteArrayToFile(final File file, final byte[] data) throws IOException {
3313 writeByteArrayToFile(file, data, false);
3314 }
3315
3316 /**
3317 * Writes a byte array to a file creating the file if it does not exist.
3318 *
3319 * @param file the file to write to
3320 * @param data the content to write to the file
3321 * @param append if {@code true}, then bytes will be added to the
3322 * end of the file rather than overwriting
3323 * @throws IOException in case of an I/O error
3324 * @since 2.1
3325 */
3326 public static void writeByteArrayToFile(final File file, final byte[] data, final boolean append) throws IOException {
3327 writeByteArrayToFile(file, data, 0, data.length, append);
3328 }
3329
3330 /**
3331 * Writes {@code len} bytes from the specified byte array starting
3332 * at offset {@code off} to a file, creating the file if it does
3333 * not exist.
3334 *
3335 * @param file the file to write to
3336 * @param data the content to write to the file
3337 * @param off the start offset in the data
3338 * @param len the number of bytes to write
3339 * @throws IOException in case of an I/O error
3340 * @since 2.5
3341 */
3342 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len) throws IOException {
3343 writeByteArrayToFile(file, data, off, len, false);
3344 }
3345
3346 /**
3347 * Writes {@code len} bytes from the specified byte array starting
3348 * at offset {@code off} to a file, creating the file if it does
3349 * not exist.
3350 *
3351 * @param file the file to write to
3352 * @param data the content to write to the file
3353 * @param off the start offset in the data
3354 * @param len the number of bytes to write
3355 * @param append if {@code true}, then bytes will be added to the
3356 * end of the file rather than overwriting
3357 * @throws IOException in case of an I/O error
3358 * @since 2.5
3359 */
3360 public static void writeByteArrayToFile(final File file, final byte[] data, final int off, final int len, final boolean append) throws IOException {
3361 try (OutputStream out = newOutputStream(file, append)) {
3362 out.write(data, off, len);
3363 }
3364 }
3365
3366 /**
3367 * Writes the {@code toString()} value of each item in a collection to
3368 * the specified {@link File} line by line.
3369 * The default VM encoding and the default line ending will be used.
3370 *
3371 * @param file the file to write to
3372 * @param lines the lines to write, {@code null} entries produce blank lines
3373 * @throws IOException in case of an I/O error
3374 * @since 1.3
3375 */
3376 public static void writeLines(final File file, final Collection<?> lines) throws IOException {
3377 writeLines(file, null, lines, null, false);
3378 }
3379
3380 /**
3381 * Writes the {@code toString()} value of each item in a collection to
3382 * the specified {@link File} line by line.
3383 * The default VM encoding and the default line ending will be used.
3384 *
3385 * @param file the file to write to
3386 * @param lines the lines to write, {@code null} entries produce blank lines
3387 * @param append if {@code true}, then the lines will be added to the
3388 * end of the file rather than overwriting
3389 * @throws IOException in case of an I/O error
3390 * @since 2.1
3391 */
3392 public static void writeLines(final File file, final Collection<?> lines, final boolean append) throws IOException {
3393 writeLines(file, null, lines, null, append);
3394 }
3395
3396 /**
3397 * Writes the {@code toString()} value of each item in a collection to
3398 * the specified {@link File} line by line.
3399 * The default VM encoding and the specified line ending will be used.
3400 *
3401 * @param file the file to write to
3402 * @param lines the lines to write, {@code null} entries produce blank lines
3403 * @param lineEnding the line separator to use, {@code null} is system default
3404 * @throws IOException in case of an I/O error
3405 * @since 1.3
3406 */
3407 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding) throws IOException {
3408 writeLines(file, null, lines, lineEnding, false);
3409 }
3410
3411 /**
3412 * Writes the {@code toString()} value of each item in a collection to
3413 * the specified {@link File} line by line.
3414 * The default VM encoding and the specified line ending will be used.
3415 *
3416 * @param file the file to write to
3417 * @param lines the lines to write, {@code null} entries produce blank lines
3418 * @param lineEnding the line separator to use, {@code null} is system default
3419 * @param append if {@code true}, then the lines will be added to the
3420 * end of the file rather than overwriting
3421 * @throws IOException in case of an I/O error
3422 * @since 2.1
3423 */
3424 public static void writeLines(final File file, final Collection<?> lines, final String lineEnding, final boolean append) throws IOException {
3425 writeLines(file, null, lines, lineEnding, append);
3426 }
3427
3428 /**
3429 * Writes the {@code toString()} value of each item in a collection to
3430 * the specified {@link File} line by line.
3431 * The specified character encoding and the default line ending will be used.
3432 * The parent directories of the file will be created if they do not exist.
3433 *
3434 * @param file the file to write to
3435 * @param charsetName the name of the requested charset, {@code null} means platform default
3436 * @param lines the lines to write, {@code null} entries produce blank lines
3437 * @throws IOException in case of an I/O error
3438 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3439 * @since 1.1
3440 */
3441 public static void writeLines(final File file, final String charsetName, final Collection<?> lines) throws IOException {
3442 writeLines(file, charsetName, lines, null, false);
3443 }
3444
3445 /**
3446 * Writes the {@code toString()} value of each item in a collection to
3447 * the specified {@link File} line by line, optionally appending.
3448 * The specified character encoding and the default line ending will be used.
3449 *
3450 * @param file the file to write to
3451 * @param charsetName the name of the requested charset, {@code null} means platform default
3452 * @param lines the lines to write, {@code null} entries produce blank lines
3453 * @param append if {@code true}, then the lines will be added to the
3454 * end of the file rather than overwriting
3455 * @throws IOException in case of an I/O error
3456 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3457 * @since 2.1
3458 */
3459 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final boolean append) throws IOException {
3460 writeLines(file, charsetName, lines, null, append);
3461 }
3462
3463 /**
3464 * Writes the {@code toString()} value of each item in a collection to
3465 * the specified {@link File} line by line.
3466 * The specified character encoding and the line ending will be used.
3467 * The parent directories of the file will be created if they do not exist.
3468 *
3469 * @param file the file to write to
3470 * @param charsetName the name of the requested charset, {@code null} means platform default
3471 * @param lines the lines to write, {@code null} entries produce blank lines
3472 * @param lineEnding the line separator to use, {@code null} is system default
3473 * @throws IOException in case of an I/O error
3474 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3475 * @since 1.1
3476 */
3477 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding) throws IOException {
3478 writeLines(file, charsetName, lines, lineEnding, false);
3479 }
3480
3481 /**
3482 * Writes the {@code toString()} value of each item in a collection to
3483 * the specified {@link File} line by line.
3484 * The specified character encoding and the line ending will be used.
3485 *
3486 * @param file the file to write to
3487 * @param charsetName the name of the requested charset, {@code null} means platform default
3488 * @param lines the lines to write, {@code null} entries produce blank lines
3489 * @param lineEnding the line separator to use, {@code null} is system default
3490 * @param append if {@code true}, then the lines will be added to the
3491 * end of the file rather than overwriting
3492 * @throws IOException in case of an I/O error
3493 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3494 * @since 2.1
3495 */
3496 public static void writeLines(final File file, final String charsetName, final Collection<?> lines, final String lineEnding, final boolean append)
3497 throws IOException {
3498 try (OutputStream out = new BufferedOutputStream(newOutputStream(file, append))) {
3499 IOUtils.writeLines(lines, lineEnding, out, charsetName);
3500 }
3501 }
3502
3503 /**
3504 * Writes a String to a file creating the file if it does not exist using the virtual machine's {@linkplain Charset#defaultCharset() default charset}.
3505 *
3506 * @param file the file to write
3507 * @param data the content to write to the file
3508 * @throws IOException in case of an I/O error
3509 * @deprecated Use {@link #writeStringToFile(File, String, Charset)} instead (and specify the appropriate encoding)
3510 */
3511 @Deprecated
3512 public static void writeStringToFile(final File file, final String data) throws IOException {
3513 writeStringToFile(file, data, Charset.defaultCharset(), false);
3514 }
3515
3516 /**
3517 * Writes a String to a file creating the file if it does not exist using the virtual machine's {@linkplain Charset#defaultCharset() default charset}.
3518 *
3519 * @param file the file to write
3520 * @param data the content to write to the file
3521 * @param append if {@code true}, then the String will be added to the end of the file rather than overwriting
3522 * @throws IOException in case of an I/O error
3523 * @since 2.1
3524 * @deprecated Use {@link #writeStringToFile(File, String, Charset, boolean)} instead (and specify the appropriate encoding)
3525 */
3526 @Deprecated
3527 public static void writeStringToFile(final File file, final String data, final boolean append) throws IOException {
3528 writeStringToFile(file, data, Charset.defaultCharset(), append);
3529 }
3530
3531 /**
3532 * Writes a String to a file creating the file if it does not exist.
3533 * The parent directories of the file will be created if they do not exist.
3534 *
3535 * @param file the file to write
3536 * @param data the content to write to the file
3537 * @param charset the charset to use, {@code null} means platform default
3538 * @throws IOException in case of an I/O error
3539 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3540 * @since 2.4
3541 */
3542 public static void writeStringToFile(final File file, final String data, final Charset charset) throws IOException {
3543 writeStringToFile(file, data, charset, false);
3544 }
3545
3546 /**
3547 * Writes a String to a file, creating the file if it does not exist.
3548 * The parent directories of the file are created if they do not exist.
3549 *
3550 * @param file the file to write
3551 * @param data the content to write to the file
3552 * @param charset the charset to use, {@code null} means platform default
3553 * @param append if {@code true}, then the String will be added to the
3554 * end of the file rather than overwriting
3555 * @throws IOException in case of an I/O error
3556 * @since 2.3
3557 */
3558 public static void writeStringToFile(final File file, final String data, final Charset charset, final boolean append) throws IOException {
3559 try (OutputStream out = newOutputStream(file, append)) {
3560 IOUtils.write(data, out, charset);
3561 }
3562 }
3563
3564 /**
3565 * Writes a String to a file, creating the file if it does not exist.
3566 * The parent directories of the file are created if they do not exist.
3567 *
3568 * @param file the file to write
3569 * @param data the content to write to the file
3570 * @param charsetName the name of the requested charset, {@code null} means platform default
3571 * @throws IOException in case of an I/O error
3572 * @throws java.io.UnsupportedEncodingException if the encoding is not supported by the VM
3573 */
3574 public static void writeStringToFile(final File file, final String data, final String charsetName) throws IOException {
3575 writeStringToFile(file, data, charsetName, false);
3576 }
3577
3578 /**
3579 * Writes a String to a file, creating the file if it does not exist.
3580 * The parent directories of the file are created if they do not exist.
3581 *
3582 * @param file the file to write
3583 * @param data the content to write to the file
3584 * @param charsetName the name of the requested charset, {@code null} means platform default
3585 * @param append if {@code true}, then the String will be added to the
3586 * end of the file rather than overwriting
3587 * @throws IOException in case of an I/O error
3588 * @throws java.nio.charset.UnsupportedCharsetException if the encoding is not supported by the VM
3589 * @since 2.1
3590 */
3591 public static void writeStringToFile(final File file, final String data, final String charsetName, final boolean append) throws IOException {
3592 writeStringToFile(file, data, Charsets.toCharset(charsetName), append);
3593 }
3594
3595 /**
3596 * Instances should NOT be constructed in standard programming.
3597 *
3598 * @deprecated TODO Make private in 3.0.
3599 */
3600 @Deprecated
3601 public FileUtils() { //NOSONAR
3602 // empty
3603 }
3604
3605 }