在Java中獲取不帶擴展名的文件名

1.概述

當我們使用Java處理文件時,經常需要處理文件名。例如,有時我們想從給定的文件名中獲取不帶擴展名的名稱。換句話說,我們要刪除文件名的擴展名。

在本教程中,我們將討論從文件名中刪除擴展名的通用方法。

2.從文件名中刪除擴展名的方案

當我們初看它時,我們可能會認為從文件名中刪除擴展名是一個非常容易的問題。

但是,如果我們仔細研究這個問題,它可能比我們想像的要復雜。

首先,讓我們看一下文件名可以是的類型:

  • 沒有任何擴展名,例如“ baeldung”
  • 對於單個擴展名,這是最常見的情況,例如“ baeldung.txt
  • 具有多個擴展名,例如“ baeldung.tar.gz
  • 沒有擴展名的Dotfile,例如“ .baeldung
  • 帶有單個擴展名的Dotfile,例如“ .baeldung.conf
  • 點文件具有多個擴展名,例如“ .baeldung.conf.bak

接下來,在刪除擴展名之後,我們將列出上述示例的預期結果:

  • baeldung ”:文件名沒有擴展名。因此,不應更改文件名,而應獲取“ baeldung
  • baeldung.txt ”:這是一個簡單的例子。正確的結果是“ baeldung
  • baeldung.tar.gz ”:此文件名包含兩個擴展名。如果只想刪除一個擴展名,則應為baeldung.tar但是,如果我們要從文件名中刪除所有擴展名,則“ baeldung ”是正確的結果
  • .baeldung ”:由於此文件名也沒有任何擴展名,因此也不應該更改文件名。因此,我們期望在結果中.baeldung
  • .baeldung.conf ”:結果應為“ .baeldung
  • .baeldung.conf.bak ”:如果我們只想刪除一個擴展名,則結果應為“ .baeldung.conf”。否則,如果我們刪除所有擴展名,則“ .baeldung

在本教程中,我們將測試Guava和Apache Commons IO提供的實用程序方法是否可以處理上面列出的所有情況。

此外,我們還將討論一種通用方法來解決從給定文件名中刪除擴展名的問題。

3.測試番石榴庫

從14.0版開始, Guava引入了[Files.getNameWithoutExtension()](https://guava.dev/releases/30.0-jre/api/docs/com/google/common/io/Files.html#getNameWithoutExtension(java.lang.String))方法。它使我們可以輕鬆地從給定文件名中刪除擴展名。

要使用實用程序方法,我們需要將Guava庫添加到我們的類路徑中。例如,如果我們使用Maven作為構建工具,則可以將Guava依賴項添加到我們的pom.xml文件中:

<dependency>

 <groupId>com.google.guava</groupId>

 <artifactId>guava</artifactId>

 <version>30.0-jre</version>

 </dependency>

首先,讓我們看一下該方法的實現:

public static String getNameWithoutExtension(String file) {

 ...

 int dotIndex = fileName.lastIndexOf('.');

 return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);

 }

實現非常簡單。如果文件名包含點,則該方法將從文件名的最後一個點切到末尾。否則,如果文件名不包含點,則將返回原始文件名,而不會進行任何更改。

因此,番石榴的getNameWithoutExtension()方法不適用於沒有擴展名的點文件。讓我們編寫一個測試來證明:

@Test

 public void givenDotFileWithoutExt_whenCallGuavaMethod_thenCannotGetDesiredResult() {

 //negative assertion

 assertNotEquals(".baeldung", Files.getNameWithoutExtension(".baeldung"));

 }

當我們處理具有多個擴展名的文件名時,此方法沒有提供從文件名中刪除所有擴展名的選項:

@Test

 public void givenFileWithoutMultipleExt_whenCallGuavaMethod_thenCannotRemoveAllExtensions() {

 //negative assertion

 assertNotEquals("baeldung", Files.getNameWithoutExtension("baeldung.tar.gz"));

 }

4.測試Apache Commons IO庫

與Guava庫一樣,流行的Apache Commons IO FilenameUtils類中提供了[removeExtension()](https://commons.apache.org/proper/commons-io/apidocs/org/apache/commons/io/FilenameUtils.html#removeExtension-java.lang.String-)方法,以快速刪除文件名的擴展名。

在研究此方法之前,讓我們將Apache Commons IO依賴項添加到我們的pom.xml

<dependency>

 <groupId>commons-io</groupId>

 <artifactId>commons-io</artifactId>

 <version>2.8.0</version>

 </dependency>

該實現類似於Guava的getNameWithoutExtension()方法:

public static String removeExtension(final String filename) {

 ...

 final int index = indexOfExtension(filename); //used the String.lastIndexOf() method

 if (index == NOT_FOUND) {


 return filename;

 } else {


 return filename.substring(0, index);

 }

 }

因此, Apache Commons IO的方法也不適用於dotfiles

@Test

 public void givenDotFileWithoutExt_whenCallApacheCommonsMethod_thenCannotGetDesiredResult() {

 //negative assertion

 assertNotEquals(".baeldung", FilenameUtils.removeExtension(".baeldung"));

 }

如果文件名具有多個擴展名,則removeExtension()方法無法刪除所有擴展名:

@Test

 public void givenFileWithoutMultipleExt_whenCallApacheCommonsMethod_thenCannotRemoveAllExtensions() {

 //negative assertion

 assertNotEquals("baeldung", FilenameUtils.removeExtension("baeldung.tar.gz"));

 }

5.從文件名中刪除擴展名

到目前為止,我們已經看到了用於從兩個廣泛使用的庫中的文件名中刪除擴展名的實用方法。兩種方法都非常方便,並且適用於最常見的情況。

但是,另一方面,它們也有一些缺點:

  • 它們不適用於點文件,例如“ .baeldung
  • 當文件名具有多個擴展名時,它們不提供僅刪除最後一個擴展名或所有擴展名的選項

接下來,讓我們構建一個涵蓋所有情況的方法:

public static String removeFileExtension(String filename, boolean removeAllExtensions) {

 if (filename == null || filename.isEmpty()) {

 return filename;

 }



 String extPattern = "(?<!^)[.]" + (removeAllExtensions ? ".*" : "[^.]*$");

 return filename.replaceAll(extPattern, "");

 }

我們添加了一個boolean參數removeAllExtensions以提供從文件名中刪除所有擴展名或僅最後一個擴展名的選項。

此方法的核心部分是regex模式。因此,讓我們了解一下此regex模式的作用:

  • “(?<!^)[.]” –我們在此regex使用了反面的表情。它匹配一個點“ . ”,而不是文件名的開頭
  • (?<!^)[.].* ” –如果removeAllExtensions選項,它將匹配第一個匹配的點,直到文件名的末尾
  • (?<!^)[.][^.]*$ ” –此模式僅匹配最後一個擴展名

最後,讓我們編寫一些測試方法來驗證我們的方法是否適用於所有不同情況:

@Test

 public void givenFilenameNoExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung", true));

 assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung", false));

 }



 @Test

 public void givenSingleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.txt", true));

 assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.txt", false));

 }



 @Test

 public void givenDotFile_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung", true));

 assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung", false));

 }



 @Test

 public void givenDotFileWithExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf", true));

 assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf", false));

 }



 @Test

 public void givenDoubleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals("baeldung", MyFilenameUtil.removeFileExtension("baeldung.tar.gz", true));

 assertEquals("baeldung.tar", MyFilenameUtil.removeFileExtension("baeldung.tar.gz", false));

 }



 @Test

 public void givenDotFileWithDoubleExt_whenCallFilenameUtilMethod_thenGetExpectedFilename() {

 assertEquals(".baeldung", MyFilenameUtil.removeFileExtension(".baeldung.conf.bak", true));

 assertEquals(".baeldung.conf", MyFilenameUtil.removeFileExtension(".baeldung.conf.bak", false));

 }

六,結論

在本文中,我們討論瞭如何從給定文件名中刪除擴展名。

首先,我們討論了刪除擴展的不同方案。

接下來,我們介紹了兩個廣泛使用的庫提供的方法:Guava和Apache Commons IO。它們非常方便,適用於常見情況,但不適用於點文件。此外,他們沒有提供刪除單個擴展名或所有擴展名的選項。

最後,我們構建了一種滿足所有需求的方法。