This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
commit fd7c8182d2117d01f43ccc9fe939105f834ba672 Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Tue Jun 14 17:34:05 2022 -0400 Add PathUtils.touch(Path) Refactor --- src/changes/changes.xml | 3 ++ src/main/java/org/apache/commons/io/FileUtils.java | 19 ++++------- .../java/org/apache/commons/io/file/PathUtils.java | 21 ++++++++++++ .../java/org/apache/commons/io/FileUtilsTest.java | 8 ++--- .../org/apache/commons/io/file/PathUtilsTest.java | 39 ++++++++++++++++++++++ 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c9db4116..31122869 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -368,6 +368,9 @@ The <action> type attribute can be add,update,fix,remove. <action dev="ggregory" type="add" due-to="Gary Gregory"> Reduce boilerplate through new UncheckedIO class and friends in org.apache.commons.io.function. </action> + <action dev="ggregory" type="add" due-to="Gary Gregory"> + Add PathUtils.touch(Path). + </action> <!-- UPDATE --> <action dev="kinow" type="update" due-to="Dependabot, Gary Gregory"> Bump actions/cache from 2.1.6 to 3.0.4 #307, #337. diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java index 6bda85a4..c2d8945b 100644 --- a/src/main/java/org/apache/commons/io/FileUtils.java +++ b/src/main/java/org/apache/commons/io/FileUtils.java @@ -70,7 +70,6 @@ import org.apache.commons.io.file.Counters; import org.apache.commons.io.file.PathFilter; import org.apache.commons.io.file.PathUtils; import org.apache.commons.io.file.StandardDeleteOption; -import org.apache.commons.io.file.attribute.FileTimes; import org.apache.commons.io.filefilter.FileEqualsFileFilter; import org.apache.commons.io.filefilter.FileFileFilter; import org.apache.commons.io.filefilter.IOFileFilter; @@ -3050,25 +3049,19 @@ public class FileUtils { } /** - * Implements the same behavior as the "touch" utility on Unix. It creates - * a new file with size 0 or, if the file exists already, it is opened and - * closed without modifying it, but updating the file date and time. + * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just + * updates the file's modified time. * <p> - * NOTE: As from v1.3, this method throws an IOException if the last - * modified date of the file cannot be set. Also, as from v1.3 this method - * creates parent directories if they do not exist. + * NOTE: As from v1.3, this method throws an IOException if the last modified date of the file cannot be set. Also, as + * from v1.3 this method creates parent directories if they do not exist. * </p> * * @param file the File to touch. * @throws NullPointerException if the parameter is {@code null}. - * @throws IOException if setting the last-modified time failed or an I/O problem occurs. + * @throws IOException if setting the last-modified time failed or an I/O problem occurs. */ public static void touch(final File file) throws IOException { - Objects.requireNonNull(file, "file"); - if (!file.exists()) { - newOutputStream(file, false).close(); - } - FileTimes.setLastModifiedTime(file.toPath()); + PathUtils.touch(Objects.requireNonNull(file, "file").toPath()); } /** diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java b/src/main/java/org/apache/commons/io/file/PathUtils.java index 2c56895a..be7e216b 100644 --- a/src/main/java/org/apache/commons/io/file/PathUtils.java +++ b/src/main/java/org/apache/commons/io/file/PathUtils.java @@ -71,6 +71,7 @@ import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.io.UncheckedIO; import org.apache.commons.io.file.Counters.PathCounters; +import org.apache.commons.io.file.attribute.FileTimes; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.function.IOFunction; @@ -1533,6 +1534,26 @@ public final class PathUtils { return fileVisitOptions == null ? EnumSet.noneOf(FileVisitOption.class) : Stream.of(fileVisitOptions).collect(Collectors.toSet()); } + /** + * Implements behavior similar to the Unix "touch" utility. Creates a new file with size 0, or, if the file exists, just + * updates the file's modified time. + * + * @param file the file to touch. + * @return The given file. + * @throws NullPointerException if the parameter is {@code null}. + * @throws IOException if setting the last-modified time failed or an I/O problem occurs.\ + * @since 2.12.0 + */ + public static Path touch(final Path file) throws IOException { + Objects.requireNonNull(file, "file"); + if (!Files.exists(file)) { + Files.createFile(file); + } else { + FileTimes.setLastModifiedTime(file); + } + return file; + } + /** * Performs {@link Files#walkFileTree(Path,FileVisitor)} and returns the given visitor. * diff --git a/src/test/java/org/apache/commons/io/FileUtilsTest.java b/src/test/java/org/apache/commons/io/FileUtilsTest.java index 2108582b..1d431c14 100644 --- a/src/test/java/org/apache/commons/io/FileUtilsTest.java +++ b/src/test/java/org/apache/commons/io/FileUtilsTest.java @@ -2700,10 +2700,10 @@ public class FileUtilsTest extends AbstractTempDirTest { assertFalse(file.exists(), "Bad test: test file still exists"); FileUtils.touch(file); assertTrue(file.exists(), "FileUtils.touch() created file"); - final OutputStream out = Files.newOutputStream(file.toPath()); - assertEquals(0, file.length(), "Created empty file."); - out.write(0); - out.close(); + try (final OutputStream out = Files.newOutputStream(file.toPath())) { + assertEquals(0, file.length(), "Created empty file."); + out.write(0); + } assertEquals(1, file.length(), "Wrote one byte to file"); final long y2k = new GregorianCalendar(2000, 0, 1).getTime().getTime(); final boolean res = setLastModifiedMillis(file, y2k); // 0L fails on Win98 diff --git a/src/test/java/org/apache/commons/io/file/PathUtilsTest.java b/src/test/java/org/apache/commons/io/file/PathUtilsTest.java index 6f53093f..bc76f7fd 100644 --- a/src/test/java/org/apache/commons/io/file/PathUtilsTest.java +++ b/src/test/java/org/apache/commons/io/file/PathUtilsTest.java @@ -20,7 +20,9 @@ package org.apache.commons.io.file; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrowsExactly; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assumptions.assumeFalse; @@ -39,11 +41,14 @@ import java.nio.file.LinkOption; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.DosFileAttributeView; +import java.nio.file.attribute.FileTime; import java.nio.file.attribute.PosixFileAttributes; +import java.util.GregorianCalendar; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.test.TestUtils; import org.apache.commons.lang3.ArrayUtils; @@ -84,6 +89,10 @@ public class PathUtilsTest extends AbstractTempDirTest { return symlinkDir; } + private Long getLastModifiedMillis(final Path file) throws IOException { + return Files.getLastModifiedTime(file).toMillis(); + } + private FileSystem openArchive(final Path p, final boolean createNew) throws IOException { if (createNew) { final Map<String, String> env = new HashMap<>(); @@ -95,6 +104,10 @@ public class PathUtilsTest extends AbstractTempDirTest { return FileSystems.newFileSystem(p, (ClassLoader) null); } + private void setLastModifiedMillis(final Path file, final long millis) throws IOException { + Files.setLastModifiedTime(file, FileTime.fromMillis(millis)); + } + @Test public void testCopyDirectoryForDifferentFilesystemsWithAbsolutePath() throws IOException { final Path archivePath = Paths.get(TEST_JAR_PATH); @@ -407,6 +420,32 @@ public class PathUtilsTest extends AbstractTempDirTest { PathUtils.deleteFile(resolved); } + @Test + public void testTouch() throws IOException { + assertThrows(NullPointerException.class, () -> FileUtils.touch(null)); + + final Path file = managedTempDirPath.resolve("touch.txt"); + Files.deleteIfExists(file); + assertFalse(Files.exists(file), "Bad test: test file still exists"); + PathUtils.touch(file); + assertTrue(Files.exists(file), "touch() created file"); + try (final OutputStream out = Files.newOutputStream(file)) { + assertEquals(0, Files.size(file), "Created empty file."); + out.write(0); + } + assertEquals(1, Files.size(file), "Wrote one byte to file"); + final long y2k = new GregorianCalendar(2000, 0, 1).getTime().getTime(); + setLastModifiedMillis(file, y2k); // 0L fails on Win98 + assertEquals(y2k, getLastModifiedMillis(file), "Bad test: set lastModified set incorrect value"); + final long nowMillis = System.currentTimeMillis(); + PathUtils.touch(file); + assertEquals(1, Files.size(file), "FileUtils.touch() didn't empty the file."); + assertNotEquals(y2k, getLastModifiedMillis(file), "FileUtils.touch() changed lastModified"); + final int delta = 3000; + assertTrue(getLastModifiedMillis(file) >= nowMillis - delta, "FileUtils.touch() changed lastModified to more than now-3s"); + assertTrue(getLastModifiedMillis(file) <= nowMillis + delta, "FileUtils.touch() changed lastModified to less than now+3s"); + } + @Test public void testWriteStringToFile1() throws Exception { final Path file = tempDirPath.resolve("write.txt");