Skip to content

Commit

Permalink
Add PathUtils.touch(Path)
Browse files Browse the repository at this point in the history
Refactor
  • Loading branch information
Gary Gregory committed Jun 14, 2022
1 parent cdc97d8 commit fd7c818
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 17 deletions.
3 changes: 3 additions & 0 deletions src/changes/changes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
19 changes: 6 additions & 13 deletions src/main/java/org/apache/commons/io/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@
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;
Expand Down Expand Up @@ -3050,25 +3049,19 @@ private static String[] toSuffixes(final String... extensions) {
}

/**
* 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());
}

/**
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/org/apache/commons/io/file/PathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
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;

Expand Down Expand Up @@ -1533,6 +1534,26 @@ static Set<FileVisitOption> toFileVisitOptionSet(final FileVisitOption... fileVi
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.
*
Expand Down
8 changes: 4 additions & 4 deletions src/test/java/org/apache/commons/io/FileUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2700,10 +2700,10 @@ public void testTouch() throws IOException {
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
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/org/apache/commons/io/file/PathUtilsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
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;
Expand All @@ -39,11 +41,14 @@
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;
Expand Down Expand Up @@ -84,6 +89,10 @@ private Path createTempSymlinkedRelativeDir() throws IOException {
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<>();
Expand All @@ -95,6 +104,10 @@ private FileSystem openArchive(final Path p, final boolean createNew) throws IOE
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);
Expand Down Expand Up @@ -407,6 +420,32 @@ public void testSetReadOnlyFile() throws IOException {
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");
Expand Down

0 comments on commit fd7c818

Please sign in to comment.