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