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。它们非常方便,适用于常见情况,但不适用于点文件。此外,他们没有提供删除单个扩展名或所有扩展名的选项。
最后,我们构建了一种满足所有需求的方法。
0 评论