Add and use PathUtils.isOlder(Path, FileTime, LinkOption...)
Add and use PathUtils.isOlder(Path, Instant, LinkOption...)
Add and use PathUtils.isOlder(Path, long, LinkOption...)
Add and use PathUtils.isOlder(Path, Path)
Add FileUtils.byteCountToDisplaySize(Number)
MODIFY
src/changes/changes.xml
src/changes/changes.xml
@@ -184,6 +184,12 @@ The <action> type attribute can be add,update,fix,remove.
Add and use PathUtils.isNewer(Path, Path) for more precision.
Add and use FileUtils.isNewer(File, FileTime) for more precision.
</action>
+ <action dev="ggregory" type="add" due-to="Gary Gregory">
+ Add and use PathUtils.isOlder(Path, FileTime, LinkOption...)
+ Add and use PathUtils.isOlder(Path, Instant, LinkOption...)
+ Add and use PathUtils.isOlder(Path, long, LinkOption...)
+ Add and use PathUtils.isOlder(Path, Path)
+ </action>
<!-- UPDATE -->
<action dev="ggregory" type="add" due-to="Gary Gregory">
Update FileEntry to use FileTime instead of long for file time stamps.

MODIFY
src/main/java/org/apache/commons/io/FileUtils.java
src/main/java/org/apache/commons/io/FileUtils.java
@@ -266,6 +266,26 @@ public static String byteCountToDisplaySize(final long size) {
return byteCountToDisplaySize(BigInteger.valueOf(size));
}
+ /**
+ * Returns a human-readable version of the file size, where the input represents a specific number of bytes.
+ * <p>
+ * If the size is over 1GB, the size is returned as the number of whole GB, i.e. the size is rounded down to the
+ * nearest GB boundary.
+ * </p>
+ * <p>
+ * Similarly for the 1MB and 1KB boundaries.
+ * </p>
+ *
+ * @param size the number of bytes
+ * @return a human-readable display value (includes units - EB, PB, TB, GB, MB, KB or bytes)
+ * @see <a href="https://issues.apache.org/jira/browse/IO-226">IO-226 - should the rounding be changed?</a>
+ * @since 2.12.0
+ */
+ // See https://issues.apache.org/jira/browse/IO-226 - should the rounding be changed?
+ public static String byteCountToDisplaySize(final Number size) {
+ return byteCountToDisplaySize(size.longValue());
+ }
+
/**
* Computes the checksum of a file using the specified checksum object. Multiple files may be checked using one
* {@code Checksum} instance if desired simply by reusing the same checksum object. For example:
@@ -1560,22 +1580,6 @@ public static boolean isFileNewer(final File file, final ChronoLocalDate chronoL
return isFileNewer(file, chronoLocalDate, LocalTime.now());
}
- /**
- * Tests if the specified {@code File} is newer than the specified {@code FileTime}.
- *
- * @param file the {@code File} of which the modification date must be compared.
- * @param fileTime the file time reference.
- * @return true if the {@code File} exists and has been modified after the given {@code FileTime}.
- * @throws IOException if an I/O error occurs.
- * @throws NullPointerException if the file or local date is {@code null}.
- *
- * @since 2.12.0
- */
- public static boolean isFileNewer(final File file, final FileTime fileTime) throws IOException {
- Objects.requireNonNull(file, "file");
- return PathUtils.isNewer(file.toPath(), fileTime);
- }
-
/**
* Tests if the specified {@code File} is newer than the specified {@code ChronoLocalDate}
* at the specified time.
@@ -1695,6 +1699,22 @@ public static boolean isFileNewer(final File file, final File reference) {
}
}
+ /**
+ * Tests if the specified {@code File} is newer than the specified {@code FileTime}.
+ *
+ * @param file the {@code File} of which the modification date must be compared.
+ * @param fileTime the file time reference.
+ * @return true if the {@code File} exists and has been modified after the given {@code FileTime}.
+ * @throws IOException if an I/O error occurs.
+ * @throws NullPointerException if the file or local date is {@code null}.
+ *
+ * @since 2.12.0
+ */
+ public static boolean isFileNewer(final File file, final FileTime fileTime) throws IOException {
+ Objects.requireNonNull(file, "file");
+ return PathUtils.isNewer(file.toPath(), fileTime);
+ }
+
/**
* Tests if the specified {@code File} is newer than the specified {@code Instant}.
*
@@ -1864,7 +1884,28 @@ public static boolean isFileOlder(final File file, final Date date) {
*/
public static boolean isFileOlder(final File file, final File reference) {
requireExists(reference, "reference");
- return isFileOlder(file, lastModifiedUnchecked(reference));
+ try {
+ return PathUtils.isOlder(file.toPath(), reference.toPath());
+ } catch (final IOException e) {
+ // TODO Update method signature
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ /**
+ * Tests if the specified {@code File} is older than the specified {@code FileTime}.
+ *
+ * @param file the {@code File} of which the modification date must be compared.
+ * @param fileTime the file time reference.
+ * @return true if the {@code File} exists and has been modified before the given {@code FileTime}.
+ * @throws IOException if an I/O error occurs.
+ * @throws NullPointerException if the file or local date is {@code null}.
+ *
+ * @since 2.12.0
+ */
+ public static boolean isFileOlder(final File file, final FileTime fileTime) throws IOException {
+ Objects.requireNonNull(file, "file");
+ return PathUtils.isOlder(file.toPath(), fileTime);
}
/**
@@ -1878,7 +1919,12 @@ public static boolean isFileOlder(final File file, final File reference) {
*/
public static boolean isFileOlder(final File file, final Instant instant) {
Objects.requireNonNull(instant, "instant");
- return isFileOlder(file, instant.toEpochMilli());
+ try {
+ return PathUtils.isOlder(file.toPath(), instant);
+ } catch (final IOException e) {
+ // TODO Update method signature
+ throw new UncheckedIOException(e);
+ }
}
/**
@@ -1892,7 +1938,12 @@ public static boolean isFileOlder(final File file, final Instant instant) {
*/
public static boolean isFileOlder(final File file, final long timeMillis) {
Objects.requireNonNull(file, "file");
- return file.exists() && lastModifiedUnchecked(file) < timeMillis;
+ try {
+ return PathUtils.isOlder(file.toPath(), timeMillis);
+ } catch (final IOException e) {
+ // TODO Update method signature
+ throw new UncheckedIOException(e);
+ }
}
/**
@@ -2008,6 +2059,9 @@ public static boolean isSymlink(final File file) {
* Returns the last modification time in milliseconds via
* {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
* <p>
+ * For the best precision, use {@link #lastModifiedFileTime(File)}.
+ * </p>
+ * <p>
* Use this method to avoid issues with {@link File#lastModified()} like
* <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
* losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.
@@ -2050,6 +2104,9 @@ public static FileTime lastModifiedFileTime(final File file) throws IOException
* Returns the last modification time in milliseconds via
* {@link java.nio.file.Files#getLastModifiedTime(Path, LinkOption...)}.
* <p>
+ * For the best precision, use {@link #lastModifiedFileTime(File)}.
+ * </p>
+ * <p>
* Use this method to avoid issues with {@link File#lastModified()} like
* <a href="https://bugs.openjdk.java.net/browse/JDK-8177809">JDK-8177809</a> where {@link File#lastModified()} is
* losing milliseconds (always ends in 000). This bug exists in OpenJDK 8 and 9, and is fixed in 10.

MODIFY
src/main/java/org/apache/commons/io/file/PathUtils.java
src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -231,7 +231,7 @@ public static PathCounters cleanDirectory(final Path directory, final DeleteOpti
* @throws NullPointerException if the file is {@code null}
*/
private static int compareLastModifiedTimeTo(final Path file, final FileTime fileTime, final LinkOption... options) throws IOException {
- return Files.getLastModifiedTime(file, options).compareTo(fileTime);
+ return getLastModifiedTime(file, options).compareTo(fileTime);
}
/**
@@ -712,6 +712,10 @@ public static boolean fileContentEquals(final Path path1, final Path path2, fina
return fileAttributeView == null ? null : fileAttributeView.getAcl();
}
+ private static FileTime getLastModifiedTime(final Path path, final LinkOption... options) throws IOException {
+ return Files.getLastModifiedTime(Objects.requireNonNull(path, "path"), options);
+ }
+
/**
* Returns a {@link Path} representing the system temporary directory.
*
@@ -819,8 +823,7 @@ public static boolean isNewer(final Path file, final FileTime fileTime, final Li
*
* @param file the {@code Path} of which the modification date must be compared
* @param instant the time reference.
- * @param options options indicating how symbolic links are handled * @return true if the {@code Path} exists and has
- * been modified after the given time reference.
+ * @param options options indicating how symbolic links are handled.
* @return true if the {@code Path} exists and has been modified after the given time reference.
* @throws IOException if an I/O error occurs.
* @throws NullPointerException if the file is {@code null}
@@ -835,8 +838,7 @@ public static boolean isNewer(final Path file, final Instant instant, final Link
*
* @param file the {@code Path} of which the modification date must be compared
* @param timeMillis the time reference measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)
- * @param options options indicating how symbolic links are handled * @return true if the {@code Path} exists and has
- * been modified after the given time reference.
+ * @param options options indicating how symbolic links are handled.
* @return true if the {@code Path} exists and has been modified after the given time reference.
* @throws IOException if an I/O error occurs.
* @throws NullPointerException if the file is {@code null}
@@ -857,7 +859,68 @@ public static boolean isNewer(final Path file, final long timeMillis, final Link
* @since 2.12.0
*/
public static boolean isNewer(final Path file, final Path reference) throws IOException {
- return isNewer(file, Files.getLastModifiedTime(reference));
+ return isNewer(file, getLastModifiedTime(reference));
+ }
+
+ /**
+ * Tests if the specified {@code Path} is older than the specified time reference.
+ *
+ * @param file the {@code Path} of which the modification date must be compared.
+ * @param fileTime the time reference.
+ * @param options options indicating how symbolic links are handled been modified after the given time reference.
+ * @return true if the {@code Path} exists and has been modified before the given time reference.
+ * @throws IOException if an I/O error occurs.
+ * @throws NullPointerException if the file is {@code null}
+ * @since 2.12.0
+ */
+ public static boolean isOlder(final Path file, final FileTime fileTime, final LinkOption... options) throws IOException {
+ if (notExists(file)) {
+ return false;
+ }
+ return compareLastModifiedTimeTo(file, fileTime, options) < 0;
+ }
+
+ /**
+ * Tests if the specified {@code Path} is older than the specified time reference.
+ *
+ * @param file the {@code Path} of which the modification date must be compared.
+ * @param instant the time reference.
+ * @param options options indicating how symbolic links are handled.
+ * @return true if the {@code Path} exists and has been modified after the given time reference.
+ * @throws IOException if an I/O error occurs.
+ * @throws NullPointerException if the file is {@code null}
+ * @since 2.12.0
+ */
+ public static boolean isOlder(final Path file, final Instant instant, final LinkOption... options) throws IOException {
+ return isOlder(file, FileTime.from(instant), options);
+ }
+
+ /**
+ * Tests if the specified {@code Path} is older than the specified time reference.
+ *
+ * @param file the {@code Path} of which the modification date must be compared
+ * @param timeMillis the time reference measured in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)
+ * @param options options indicating how symbolic links are handled been modified after the given time reference.
+ * @return true if the {@code Path} exists and has been modified before the given time reference.
+ * @throws IOException if an I/O error occurs.
+ * @throws NullPointerException if the file is {@code null}
+ * @since 2.12.0
+ */
+ public static boolean isOlder(final Path file, final long timeMillis, final LinkOption... options) throws IOException {
+ return isOlder(file, FileTime.fromMillis(timeMillis), options);
+ }
+
+ /**
+ * Tests if the specified {@code Path} is older than the reference {@code Path}.
+ *
+ * @param file the {@code File} of which the modification date must be compared.
+ * @param reference the {@code File} of which the modification date is used.
+ * @return true if the {@code File} exists and has been modified before than the reference {@code File}.
+ * @throws IOException if an I/O error occurs.
+ * @since 2.12.0
+ */
+ public static boolean isOlder(final Path file, final Path reference) throws IOException {
+ return isOlder(file, getLastModifiedTime(reference));
}
/**
@@ -1009,7 +1072,7 @@ public static void setLastModifiedTime(final Path path) throws IOException {
*/
public static void setLastModifiedTime(final Path sourceFile, final Path targetFile) throws IOException {
Objects.requireNonNull(sourceFile, "sourceFile");
- Files.setLastModifiedTime(targetFile, Files.getLastModifiedTime(sourceFile));
+ Files.setLastModifiedTime(targetFile, getLastModifiedTime(sourceFile));
}
/**

MODIFY
src/test/java/org/apache/commons/io/FileUtilsTestCase.java
src/test/java/org/apache/commons/io/FileUtilsTestCase.java
@@ -458,6 +458,31 @@ public void testByteCountToDisplaySizeLong() {
assertEquals("1 GB", FileUtils.byteCountToDisplaySize(Integer.MAX_VALUE));
}
+ @Test
+ public void testByteCountToDisplaySizeNumber() {
+ assertEquals("0 bytes", FileUtils.byteCountToDisplaySize(Integer.valueOf(0)));
+ assertEquals("1 bytes", FileUtils.byteCountToDisplaySize(Integer.valueOf(1)));
+ assertEquals("1023 bytes", FileUtils.byteCountToDisplaySize(Integer.valueOf(1023)));
+ assertEquals("1 KB", FileUtils.byteCountToDisplaySize(Integer.valueOf(1024)));
+ assertEquals("1 KB", FileUtils.byteCountToDisplaySize(Integer.valueOf(1025)));
+ assertEquals("1023 KB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1023)));
+ assertEquals("1 MB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1024)));
+ assertEquals("1 MB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1025)));
+ assertEquals("1023 MB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1024 * 1023)));
+ assertEquals("1 GB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1024 * 1024)));
+ assertEquals("1 GB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1024 * 1025)));
+ assertEquals("2 GB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024L * 1024 * 1024 * 2)));
+ assertEquals("1 GB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024 * 1024 * 1024 * 2 - 1)));
+ assertEquals("1 TB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024L * 1024 * 1024 * 1024)));
+ assertEquals("1 PB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024L * 1024 * 1024 * 1024 * 1024)));
+ assertEquals("1 EB", FileUtils.byteCountToDisplaySize(Long.valueOf(1024L * 1024 * 1024 * 1024 * 1024 * 1024)));
+ assertEquals("7 EB", FileUtils.byteCountToDisplaySize(Long.valueOf(Long.MAX_VALUE)));
+ // Other MAX_VALUEs
+ assertEquals("63 KB", FileUtils.byteCountToDisplaySize(Integer.valueOf(Character.MAX_VALUE)));
+ assertEquals("31 KB", FileUtils.byteCountToDisplaySize(Short.valueOf(Short.MAX_VALUE)));
+ assertEquals("1 GB", FileUtils.byteCountToDisplaySize(Integer.valueOf(Integer.MAX_VALUE)));
+ }
+
@Test
public void testChecksum() throws Exception {
// create a test file

Add and use PathUtils.isOlder(Path, FileTime, LinkOption...)

- Add and use PathUtils.isOlder(Path, Instant, LinkOption...)
- Add and use PathUtils.isOlder(Path, long, LinkOption...)
- Add and use PathUtils.isOlder(Path, Path)
- Add FileUtils.byteCountToDisplaySize(Number)