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


The following commit(s) were added to refs/heads/master by this push:
     new ce52198b Add PathUtils.getExtension(Path)
ce52198b is described below

commit ce52198bee990f3c4742934821552b403a9ac0eb
Author: Gary Gregory <[email protected]>
AuthorDate: Fri Dec 22 21:44:00 2023 -0500

    Add PathUtils.getExtension(Path)
---
 src/changes/changes.xml                            |  1 +
 .../java/org/apache/commons/io/file/PathUtils.java | 26 ++++++++++++++++++++++
 .../org/apache/commons/io/file/PathUtilsTest.java  | 26 ++++++++++++++++++++++
 3 files changed, 53 insertions(+)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a28b73e0..9b5d79aa 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -90,6 +90,7 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add FileTimes.isUnixTime(long).</action>
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add FileTimes.toUnixTime(FileTime).</action>
       <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add BrokenInputStream.Builder.</action>
+      <action dev="ggregory" type="add"                due-to="Gary 
Gregory">Add PathUtils.getExtension(Path).</action>
       <!--  UPDATE -->
       <action dev="ggregory" type="fix"                due-to="Gary 
Gregory">Bump commons.bytebuddy.version from 1.14.10 to 1.14.11 #534.</action>
     </release>
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 64ca294a..0ed29d5b 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -867,6 +867,32 @@ public final class PathUtils {
         return Files.getFileAttributeView(path, DosFileAttributeView.class, 
options);
     }
 
+    /**
+     * Gets the extension of a Path.
+     * <p>
+     * This method returns the textual part of the Path after the last dot.
+     * </p>
+     * <pre>
+     * foo.txt      --&gt; "txt"
+     * a/b/c.jpg    --&gt; "jpg"
+     * a/b.txt/c    --&gt; ""
+     * a/b/c        --&gt; ""
+     * </pre>
+     * <p>
+     * The output will be the same irrespective of the machine that the code 
is running on.
+     * </p>
+     * <p>
+     *
+     * @param path the path to query.
+     * @return the extension of the file or an empty string if none exists or 
{@code null}
+     * if the fileName is {@code null}.
+     * @since 2.16.0
+     */
+    public static String getExtension(final Path path) {
+        final String fileName = getFileNameString(path);
+        return fileName != null ? FilenameUtils.getExtension(fileName) : null;
+    }
+
     /**
      * Gets the Path's file name and apply the given function if the file name 
is non-null.
      *
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 c27c39de..8a558d21 100644
--- a/src/test/java/org/apache/commons/io/file/PathUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/file/PathUtilsTest.java
@@ -246,6 +246,32 @@ public class PathUtilsTest extends AbstractTempDirTest {
         assertEquals(symlinkedDir, 
PathUtils.createParentDirectories(symlinkedDir.resolve("child")));
     }
 
+    @Test
+    public void testGetExtension() {
+        assertNull(PathUtils.getExtension(null));
+        assertEquals("ext", PathUtils.getExtension(Paths.get("file.ext")));
+        assertEquals("", PathUtils.getExtension(Paths.get("README")));
+        assertEquals("com", 
PathUtils.getExtension(Paths.get("domain.dot.com")));
+        assertEquals("jpeg", PathUtils.getExtension(Paths.get("image.jpeg")));
+        assertEquals("", PathUtils.getExtension(Paths.get("a.b/c")));
+        assertEquals("txt", PathUtils.getExtension(Paths.get("a.b/c.txt")));
+        assertEquals("", PathUtils.getExtension(Paths.get("a/b/c")));
+        assertEquals("", PathUtils.getExtension(Paths.get("a.b\\c")));
+        assertEquals("txt", PathUtils.getExtension(Paths.get("a.b\\c.txt")));
+        assertEquals("", PathUtils.getExtension(Paths.get("a\\b\\c")));
+        assertEquals("", 
PathUtils.getExtension(Paths.get("C:\\temp\\foo.bar\\README")));
+        assertEquals("ext", 
PathUtils.getExtension(Paths.get("../filename.ext")));
+
+        if (File.separatorChar == '\\') {
+            // Special case handling for NTFS ADS names
+            final IllegalArgumentException e = 
assertThrows(IllegalArgumentException.class, () -> 
PathUtils.getExtension(Paths.get("foo.exe:bar.txt")));
+            assertEquals("NTFS ADS separator (':') in file name is 
forbidden.", e.getMessage());
+        } else {
+            // Upwards compatibility:
+            assertEquals("txt", 
PathUtils.getExtension(Paths.get("foo.exe:bar.txt")));
+        }
+    }
+
     @Test
     public void testGetFileName() {
         assertNull(PathUtils.getFileName(null, null));

Reply via email to