Skip to content

Commit 2bc7e31

Browse files
author
Gary Gregory
committed
Reimplement some FileUtils internals in terms of refactored PathUtils
methods to provide better behavioral compatibility with older versions like 2.6 in the area of deleting read-only file system elements. Also clean up some Javadocs.
1 parent bf47606 commit 2bc7e31

4 files changed

Lines changed: 215 additions & 134 deletions

File tree

src/main/java/org/apache/commons/io/FileUtils.java

Lines changed: 105 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -237,55 +237,6 @@ public static String byteCountToDisplaySize(final long size) {
237237
return byteCountToDisplaySize(BigInteger.valueOf(size));
238238
}
239239

240-
/**
241-
* Checks that the given {@code File} exists and is a directory.
242-
*
243-
* @param directory The {@code File} to check.
244-
* @return the given directory.
245-
* @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
246-
*/
247-
private static File checkDirectory(final File directory) {
248-
if (!directory.exists()) {
249-
throw new IllegalArgumentException(directory + " does not exist");
250-
}
251-
if (!directory.isDirectory()) {
252-
throw new IllegalArgumentException(directory + " is not a directory");
253-
}
254-
return directory;
255-
}
256-
257-
/**
258-
* Checks that two file lengths are equal.
259-
*
260-
* @param srcFile Source file.
261-
* @param destFile Destination file.
262-
* @param srcLen Source file length.
263-
* @param dstLen Destination file length
264-
* @throws IOException Thrown when the given sizes are not equal.
265-
*/
266-
private static void checkEqualSizes(final File srcFile, final File destFile, final long srcLen, final long dstLen)
267-
throws IOException {
268-
if (srcLen != dstLen) {
269-
throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile
270-
+ "' Expected length: " + srcLen + " Actual: " + dstLen);
271-
}
272-
}
273-
274-
/**
275-
* Checks requirements for file copy.
276-
*
277-
* @param source the source file
278-
* @param destination the destination
279-
* @throws FileNotFoundException if the destination does not exist
280-
*/
281-
private static void checkFileRequirements(final File source, final File destination) throws FileNotFoundException {
282-
Objects.requireNonNull(source, "source");
283-
Objects.requireNonNull(destination, "target");
284-
if (!source.exists()) {
285-
throw new FileNotFoundException("Source '" + source + "' does not exist");
286-
}
287-
}
288-
289240
/**
290241
* Computes the checksum of a file using the specified checksum object.
291242
* Multiple files may be checked using one <code>Checksum</code> instance
@@ -304,9 +255,7 @@ private static void checkFileRequirements(final File source, final File destinat
304255
* @since 1.3
305256
*/
306257
public static Checksum checksum(final File file, final Checksum checksum) throws IOException {
307-
if (file.isDirectory()) {
308-
throw new IllegalArgumentException("Checksums can't be computed on directories");
309-
}
258+
requireFile(file, "file");
310259
try (InputStream in = new CheckedInputStream(new FileInputStream(file), checksum)) {
311260
IOUtils.consume(in);
312261
}
@@ -717,7 +666,7 @@ public static void copyDirectory(final File srcDir, final File destDir, final Fi
717666
*/
718667
public static void copyDirectory(final File srcDir, final File destDir, final FileFilter filter,
719668
final boolean preserveFileDate, final CopyOption... copyOptions) throws IOException {
720-
checkFileRequirements(srcDir, destDir);
669+
requireFileRequirements(srcDir, destDir);
721670
if (!srcDir.isDirectory()) {
722671
throw new IOException("Source '" + srcDir + "' exists but is not a directory");
723672
}
@@ -875,7 +824,7 @@ public static void copyFile(final File srcFile, final File destFile, final boole
875824
*/
876825
public static void copyFile(final File srcFile, final File destFile, final boolean preserveFileDate, final CopyOption... copyOptions)
877826
throws IOException {
878-
checkFileRequirements(srcFile, destFile);
827+
requireFileRequirements(srcFile, destFile);
879828
if (srcFile.isDirectory()) {
880829
throw new IOException("Source '" + srcFile + "' exists but is a directory");
881830
}
@@ -1041,7 +990,6 @@ public static void copyToDirectory(final File sourceFile, final File destination
1041990
}
1042991
}
1043992

1044-
1045993
/**
1046994
* Copies a files to a directory preserving each file's date.
1047995
* <p>
@@ -1122,6 +1070,7 @@ public static void copyURLToFile(final URL source, final File destination) throw
11221070
}
11231071
}
11241072

1073+
11251074
/**
11261075
* Copies bytes from the URL <code>source</code> to a file
11271076
* <code>destination</code>. The directories up to <code>destination</code>
@@ -1291,20 +1240,12 @@ public static boolean deleteQuietly(final File file) {
12911240
* @param child the file to consider as the child.
12921241
* @return true is the candidate leaf is under by the specified composite. False otherwise.
12931242
* @throws IOException if an IO error occurs while checking the files.
1294-
* @throws IllegalArgumentException if {@code directory} is null or not a directory.
1243+
* @throws IllegalArgumentException if {@code directory} is not a directory.
12951244
* @see FilenameUtils#directoryContains(String, String)
12961245
* @since 2.2
12971246
*/
12981247
public static boolean directoryContains(final File directory, final File child) throws IOException {
1299-
1300-
// Fail fast against NullPointerException
1301-
if (directory == null) {
1302-
throw new IllegalArgumentException("Directory must not be null");
1303-
}
1304-
1305-
if (!directory.isDirectory()) {
1306-
throw new IllegalArgumentException("Not a directory: " + directory);
1307-
}
1248+
requireDirectory(directory, "directory");
13081249

13091250
if (child == null) {
13101251
return false;
@@ -1399,9 +1340,9 @@ private static void doCopyFile(final File srcFile, final File destFile, final bo
13991340
Files.copy(srcPath, destPath, copyOptions);
14001341

14011342
// TODO IO-386: Do we still need this check?
1402-
checkEqualSizes(srcFile, destFile, Files.size(srcPath), Files.size(destPath));
1343+
requireEqualSizes(srcFile, destFile, Files.size(srcPath), Files.size(destPath));
14031344
// TODO IO-386: Do we still need this check?
1404-
checkEqualSizes(srcFile, destFile, srcFile.length(), destFile.length());
1345+
requireEqualSizes(srcFile, destFile, srcFile.length(), destFile.length());
14051346

14061347
if (preserveFileDate) {
14071348
setLastModified(srcFile, destFile);
@@ -1426,7 +1367,8 @@ private static void doCopyFile(final File srcFile, final File destFile, final bo
14261367
public static void forceDelete(final File file) throws IOException {
14271368
final Counters.PathCounters deleteCounters;
14281369
try {
1429-
deleteCounters = PathUtils.delete(file.toPath(), StandardDeleteOption.OVERRIDE_READ_ONLY);
1370+
deleteCounters = PathUtils.delete(file.toPath(), PathUtils.EMPTY_LINK_OPTION_ARRAY,
1371+
StandardDeleteOption.OVERRIDE_READ_ONLY);
14301372
} catch (final IOException e) {
14311373
throw new IOException("Unable to delete file: " + file, e);
14321374
}
@@ -1713,11 +1655,7 @@ public static boolean isFileNewer(final File file, final Date date) {
17131655
* @throws IllegalArgumentException if the reference file doesn't exist
17141656
*/
17151657
public static boolean isFileNewer(final File file, final File reference) {
1716-
Objects.requireNonNull(reference, "reference");
1717-
if (!reference.exists()) {
1718-
throw new IllegalArgumentException("The reference file '"
1719-
+ reference + "' doesn't exist");
1720-
}
1658+
requireExists(reference, "reference");
17211659
return isFileNewer(file, reference.lastModified());
17221660
}
17231661

@@ -1882,10 +1820,7 @@ public static boolean isFileOlder(final File file, final Date date) {
18821820
* @throws IllegalArgumentException if the reference file doesn't exist
18831821
*/
18841822
public static boolean isFileOlder(final File file, final File reference) {
1885-
if (!Objects.requireNonNull(reference, "reference").exists()) {
1886-
throw new IllegalArgumentException("The reference file '"
1887-
+ reference + "' doesn't exist");
1888-
}
1823+
requireExists(reference, "reference");
18891824
return isFileOlder(file, reference.lastModified());
18901825
}
18911826

@@ -1956,7 +1891,6 @@ public static boolean isSymlink(final File file) {
19561891
* The resulting iterator MUST be consumed in its entirety in order to close its underlying stream.
19571892
* </p>
19581893
* <p>
1959-
* <p>
19601894
* All files found are filtered by an IOFileFilter.
19611895
* </p>
19621896
*
@@ -2152,6 +2086,7 @@ public static Collection<File> listFiles(final File directory, final String[] ex
21522086
throw new IllegalArgumentException(e);
21532087
}
21542088
}
2089+
21552090
/**
21562091
* Finds files within a given directory (and optionally its
21572092
* subdirectories). All files found are filtered by an IOFileFilter.
@@ -2249,7 +2184,6 @@ public static void moveDirectoryToDirectory(final File src, final File destDir,
22492184
}
22502185
moveDirectory(src, new File(destDir, src.getName()));
22512186
}
2252-
22532187
/**
22542188
* Moves a file.
22552189
* <p>
@@ -2478,7 +2412,6 @@ public static String readFileToString(final File file) throws IOException {
24782412
return readFileToString(file, Charset.defaultCharset());
24792413
}
24802414

2481-
24822415
/**
24832416
* Reads the contents of a file into a String.
24842417
* The file is always closed.
@@ -2525,6 +2458,7 @@ public static List<String> readLines(final File file) throws IOException {
25252458
return readLines(file, Charset.defaultCharset());
25262459
}
25272460

2461+
25282462
/**
25292463
* Reads the contents of a file line by line to a List of Strings.
25302464
* The file is always closed.
@@ -2556,6 +2490,86 @@ public static List<String> readLines(final File file, final String charsetName)
25562490
return readLines(file, Charsets.toCharset(charsetName));
25572491
}
25582492

2493+
/**
2494+
* Requires that the given {@code File} exists and is a directory.
2495+
*
2496+
* @param directory The {@code File} to check.
2497+
* @param param The param name to use in the exception message in case of null input.
2498+
* @return the given directory.
2499+
* @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
2500+
*/
2501+
private static File requireDirectory(final File directory, String param) {
2502+
requireExists(directory, param);
2503+
if (!directory.isDirectory()) {
2504+
throw new IllegalArgumentException(directory + " is not a directory");
2505+
}
2506+
return directory;
2507+
}
2508+
2509+
/**
2510+
* Requires that two file lengths are equal.
2511+
*
2512+
* @param srcFile Source file.
2513+
* @param destFile Destination file.
2514+
* @param srcLen Source file length.
2515+
* @param dstLen Destination file length
2516+
* @throws IOException Thrown when the given sizes are not equal.
2517+
*/
2518+
private static void requireEqualSizes(final File srcFile, final File destFile, final long srcLen, final long dstLen)
2519+
throws IOException {
2520+
if (srcLen != dstLen) {
2521+
throw new IOException("Failed to copy full contents from '" + srcFile + "' to '" + destFile
2522+
+ "' Expected length: " + srcLen + " Actual: " + dstLen);
2523+
}
2524+
}
2525+
2526+
/**
2527+
* Requires that the given {@code File} exists.
2528+
*
2529+
* @param file The {@code File} to check.
2530+
* @param param The param name to use in the exception message in case of null input.
2531+
* @return the given file.
2532+
* @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
2533+
*/
2534+
private static File requireExists(final File file, String param) {
2535+
Objects.requireNonNull(file, param);
2536+
if (!file.exists()) {
2537+
throw new IllegalArgumentException(file + " does not exist");
2538+
}
2539+
return file;
2540+
}
2541+
2542+
/**
2543+
* Requires that the given {@code File} exists and is a file.
2544+
*
2545+
* @param file The {@code File} to check.
2546+
* @param param The param name to use in the exception message in case of null input.
2547+
* @return the given file.
2548+
* @throws IllegalArgumentException if the given {@code File} does not exist or is not a directory.
2549+
*/
2550+
private static File requireFile(final File file, String param) {
2551+
requireExists(file, param);
2552+
if (!file.isFile()) {
2553+
throw new IllegalArgumentException(file + " is not a file");
2554+
}
2555+
return file;
2556+
}
2557+
2558+
/**
2559+
* Requires requirements for file copy.
2560+
*
2561+
* @param source the source file
2562+
* @param destination the destination
2563+
* @throws FileNotFoundException if the destination does not exist
2564+
*/
2565+
private static void requireFileRequirements(final File source, final File destination) throws FileNotFoundException {
2566+
Objects.requireNonNull(source, "source");
2567+
Objects.requireNonNull(destination, "target");
2568+
if (!source.exists()) {
2569+
throw new FileNotFoundException("Source '" + source + "' does not exist");
2570+
}
2571+
}
2572+
25592573
/**
25602574
* Sets the given {@code targetFile}'s last modified date to the value from {@code sourceFile}.
25612575
*
@@ -2587,16 +2601,13 @@ private static void setLastModified(final File sourceFile, final File targetFile
25872601
* @return the length of the file, or recursive size of the directory,
25882602
* provided (in bytes).
25892603
*
2590-
* @throws NullPointerException if the file is {@code null}
2604+
* @throws NullPointerException if the file is {@code null}.
25912605
* @throws IllegalArgumentException if the file does not exist.
25922606
*
25932607
* @since 2.0
25942608
*/
25952609
public static long sizeOf(final File file) {
2596-
if (!file.exists()) {
2597-
final String message = file + " does not exist";
2598-
throw new IllegalArgumentException(message);
2599-
}
2610+
requireExists(file, "file");
26002611
if (file.isDirectory()) {
26012612
return sizeOfDirectory0(file); // private method; expects directory
26022613
}
@@ -2628,16 +2639,13 @@ private static long sizeOf0(final File file) {
26282639
* @return the length of the file, or recursive size of the directory,
26292640
* provided (in bytes).
26302641
*
2631-
* @throws NullPointerException if the file is {@code null}
2642+
* @throws NullPointerException if the file is {@code null}.
26322643
* @throws IllegalArgumentException if the file does not exist.
26332644
*
26342645
* @since 2.4
26352646
*/
26362647
public static BigInteger sizeOfAsBigInteger(final File file) {
2637-
if (!file.exists()) {
2638-
final String message = file + " does not exist";
2639-
throw new IllegalArgumentException(message);
2640-
}
2648+
requireExists(file, "file");
26412649
if (file.isDirectory()) {
26422650
return sizeOfDirectoryBig0(file); // internal method
26432651
}
@@ -2664,13 +2672,13 @@ private static BigInteger sizeOfBig0(final File fileOrDir) {
26642672
* method that does not overflow.
26652673
* </p>
26662674
*
2667-
* @param directory directory to inspect, must not be {@code null}
2675+
* @param directory directory to inspect, must not be {@code null}.
26682676
* @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total
26692677
* is greater than {@link Long#MAX_VALUE}.
2670-
* @throws NullPointerException if the directory is {@code null}
2678+
* @throws NullPointerException if the directory is {@code null}.
26712679
*/
26722680
public static long sizeOfDirectory(final File directory) {
2673-
return sizeOfDirectory0(checkDirectory(directory));
2681+
return sizeOfDirectory0(requireDirectory(directory, "directory"));
26742682
}
26752683

26762684
/**
@@ -2700,13 +2708,13 @@ private static long sizeOfDirectory0(final File directory) {
27002708
/**
27012709
* Counts the size of a directory recursively (sum of the length of all files).
27022710
*
2703-
* @param directory directory to inspect, must not be {@code null}
2711+
* @param directory directory to inspect, must not be {@code null}.
27042712
* @return size of directory in bytes, 0 if directory is security restricted.
2705-
* @throws NullPointerException if the directory is {@code null}
2713+
* @throws NullPointerException if the directory is {@code null}.
27062714
* @since 2.4
27072715
*/
27082716
public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) {
2709-
return sizeOfDirectoryBig0(checkDirectory(directory));
2717+
return sizeOfDirectoryBig0(requireDirectory(directory, "directory"));
27102718
}
27112719

27122720
/**
@@ -2919,16 +2927,7 @@ private static void validateMoveParameters(final File source, final File destina
29192927
* @throws IOException if an I/O error occurs
29202928
*/
29212929
private static File[] verifiedListFiles(final File directory) throws IOException {
2922-
if (!directory.exists()) {
2923-
final String message = directory + " does not exist";
2924-
throw new IllegalArgumentException(message);
2925-
}
2926-
2927-
if (!directory.isDirectory()) {
2928-
final String message = directory + " is not a directory";
2929-
throw new IllegalArgumentException(message);
2930-
}
2931-
2930+
requireDirectory(directory, "directory");
29322931
final File[] files = directory.listFiles();
29332932
if (files == null) { // null if security restricted
29342933
throw new IOException("Failed to list contents of " + directory);

src/main/java/org/apache/commons/io/file/CleaningPathVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public static CountingPathVisitor withLongCounters() {
6060
* Constructs a new visitor that deletes files except for the files and directories explicitly given.
6161
*
6262
* @param pathCounter How to count visits.
63-
* @param deleteOption options indicating how deletion is handled.
63+
* @param deleteOption How deletion is handled.
6464
* @param skip The files to skip deleting.
6565
* @since 2.8.0
6666
*/

0 commit comments

Comments
 (0)