1. Overview
1.概述
When we work with files in Java, we often need to handle filenames. For example, sometimes we want to get the name without the extension from a given filename. In other words, we want to remove the extension of a filename.
当我们在Java中处理文件时,我们经常需要处理文件名。例如,有时我们想从一个给定的文件名中得到没有扩展名的名字。换句话说,我们想删除文件名的扩展名。
In this tutorial, we’ll discuss the generic way to remove the extension from a filename.
在本教程中,我们将讨论删除文件名扩展名的通用方法。
2. Scenarios of Removing the Extension From a Filename
2.从文件名中删除扩展名的情况
When we take a first look at it, we may think that removing the extension from a filename is a pretty easy problem.
当我们第一眼看到它时,我们可能认为从文件名中删除扩展名是一个相当容易的问题。
However, if we take a closer look at the problem, it could be more complicated than we thought.
然而,如果我们仔细看看这个问题,它可能比我们想象的更复杂。
First of all, let’s have a look at the types a filename can be:
首先,让我们看看文件名可以有哪些类型。
- Without any extension, for example, “baeldung”
- With a single extension, this is the most usual case, for example, “baeldung.txt“
- With multiple extensions, like “baeldung.tar.gz“
- Dotfile without an extension, such as “.baeldung“
- Dotfile with a single extension, for instance, “.baeldung.conf“
- Dotfile with multiple extensions, for example, “.baeldung.conf.bak“
Next, we’ll list expecting results of the examples above after removing the extension(s):
接下来,我们将列出上述例子中删除扩展名后的预期结果。
- “baeldung“: The filename doesn’t have an extension. Therefore, the filename should not be changed, and we should get “baeldung“
- “baeldung.txt“: This is a straightforward case. The correct result is “baeldung“
- “baeldung.tar.gz“: This filename contains two extensions. If we want to remove only one extension, “baeldung.tar” should be the result. But if we want to remove all extensions from the filename, “baeldung” is the correct result
- “.baeldung“: Since this filename doesn’t have any extension either, the filename shouldn’t be changed either. Thus, we’re expecting to see “.baeldung” in the result
- “.baeldung.conf“: The result should be “.baeldung“
- “.baeldung.conf.bak“: The result should be “.baeldung.conf” if we only want to remove one extension. Otherwise, “.baeldung” is the expected output if we’ll remove all extensions
In this tutorial, we’ll test if the utility methods provided by Guava and Apache Commons IO can handle all the cases listed above.
在本教程中,我们将测试Guava和Apache Commons IO提供的实用方法是否能够处理以上列出的所有情况。
Further, we’ll also discuss a generic way to solve the problem of removing the extension (or extensions) from a given filename.
此外,我们还将讨论一种解决从给定文件名中删除扩展名(或扩展名)问题的通用方法。
3. Testing the Guava Library
3.测试Guava库
Since version 14.0, Guava has introduced the Files.getNameWithoutExtension() method. It allows us to remove the extension from the given filename easily.
从14.0版本开始,Guava引入了Files.getNameWithoutExtension()方法。它允许我们轻松地从给定的文件名中删除扩展名。
To use the utility method, we need to add the Guava library into our classpath. For example, if we use Maven as the build tool, we can add the Guava dependency to our pom.xml file:
要使用该实用方法,我们需要将Guava库添加到我们的classpath中。例如,如果我们使用Maven作为构建工具,我们可以在pom.xml文件中添加Guava依赖项。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.0.1-jre</version>
</dependency>
First, let’s have a look at the implementation of this method:
首先,让我们看一下这个方法的实现。
public static String getNameWithoutExtension(String file) {
...
int dotIndex = fileName.lastIndexOf('.');
return (dotIndex == -1) ? fileName : fileName.substring(0, dotIndex);
}
The implementation is pretty straightforward. If the filename contains dots, the method cuts from the last dot to the end of the filename. Otherwise, if the filename doesn’t contain a dot, the original filename will be returned without any change.
该方法的实现非常简单明了。如果文件名包含点,该方法从最后一个点切到文件名的结尾。否则,如果文件名不包含点,将返回原始文件名,不做任何改变。
Therefore, Guava’s getNameWithoutExtension() method won’t work for dotfiles without an extension. Let’s write a test to prove that:
因此,Guava的getNameWithoutExtension()方法对没有扩展名的dotfiles不起作用。让我们写一个测试来证明这一点。
@Test
public void givenDotFileWithoutExt_whenCallGuavaMethod_thenCannotGetDesiredResult() {
//negative assertion
assertNotEquals(".baeldung", Files.getNameWithoutExtension(".baeldung"));
}
When we handle a filename with multiple extensions, this method doesn’t provide an option to remove all extensions from the filename:
当我们处理一个有多个扩展名的文件时,这个方法没有提供一个选项来删除文件名中的所有扩展名:。
@Test
public void givenFileWithoutMultipleExt_whenCallGuavaMethod_thenCannotRemoveAllExtensions() {
//negative assertion
assertNotEquals("baeldung", Files.getNameWithoutExtension("baeldung.tar.gz"));
}
4. Testing the Apache Commons IO Library
4.测试Apache Commons IO库
Like the Guava library, the popular Apache Commons IO library provides a removeExtension() method in the FilenameUtils class to quickly remove the filename’s extension.
与Guava库一样,流行的Apache Commons IO库在FilenameUtils类中提供了一个removeExtension()方法来快速删除文件名的扩展名。
Before we have a look at this method, let’s add the Apache Commons IO dependency into our pom.xml:
在看这个方法之前,我们先把Apache Commons IO依赖性添加到我们的pom.xml中。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
The implementation is similar to Guava’s getNameWithoutExtension() method:
这个实现类似于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);
}
}
Therefore, the Apache Commons IO’s method won’t work with dotfiles either:
因此,Apache Commons IO的方法对dotfiles也不起作用。
@Test
public void givenDotFileWithoutExt_whenCallApacheCommonsMethod_thenCannotGetDesiredResult() {
//negative assertion
assertNotEquals(".baeldung", FilenameUtils.removeExtension(".baeldung"));
}
If a filename has multiple extensions, the removeExtension() method cannot remove all extensions:
如果一个文件名有多个扩展名,removeExtension()方法不能删除所有扩展名:。
@Test
public void givenFileWithoutMultipleExt_whenCallApacheCommonsMethod_thenCannotRemoveAllExtensions() {
//negative assertion
assertNotEquals("baeldung", FilenameUtils.removeExtension("baeldung.tar.gz"));
}
5. Removing the Extension(s) From a Filename
5.从文件名中删除扩展名
So far, we’ve seen utility methods for removing the extension from a filename in two widely used libraries. Both methods are pretty handy and work for the most common cases.
到目前为止,我们已经看到了在两个广泛使用的库中去除文件名扩展名的实用方法。这两种方法都很方便,对最常见的情况都有效。
However, on the other hand, they have some shortcomings:
然而,另一方面,它们也有一些不足之处。
- They won’t work for dotfiles, for example, “.baeldung“
- When a filename has multiple extensions, they don’t provide an option to remove the last extension only or all extensions
Next, let’s build a method to cover all cases:
接下来,让我们建立一个涵盖所有情况的方法。
public static String removeFileExtension(String filename, boolean removeAllExtensions) {
if (filename == null || filename.isEmpty()) {
return filename;
}
String extPattern = "(?<!^)[.]" + (removeAllExtensions ? ".*" : "[^.]*$");
return filename.replaceAll(extPattern, "");
}
We added a boolean parameter removeAllExtensions to provide the option to remove all extensions or only the last extension from a filename.
我们添加了一个boolean参数removeAllExtensions,以提供从文件名中移除所有扩展名或仅移除最后一个扩展名的选项。
The core part of this method is the regex pattern. So let’s understand what does this regex pattern do:
这个方法的核心部分是regex模式。因此,让我们了解这个regex模式是做什么的。
- “(?<!^)[.]” – We use a negative-lookbehind in this regex. It matches a dot “.” that is not at the beginning of the filename
- “(?<!^)[.].*” – If the removeAllExtensions option is set, this will match the first matched dot until the end of the filename
- “(?<!^)[.][^.]*$” – This pattern matches only the last extension
Finally, let’s write some test methods to verify if our method works for all different cases:
最后,让我们写一些测试方法来验证我们的方法是否对所有不同的情况都有效。
@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));
}
6. Conclusion
6.结语
In this article, we’ve talked about how to remove extensions from a given filename.
在这篇文章中,我们已经谈到了如何从一个给定的文件名中删除扩展名。
First, we discussed the different scenarios of removing extensions.
首先,我们讨论了删除扩展功能的不同情况。
Next, we’ve introduced the methods provided by two widely used libraries: Guava and Apache Commons IO. They are pretty handy and work for common cases but cannot work for dotfiles. Also, they don’t provide an option to remove a single extension or all extensions.
接下来,我们已经介绍了两个广泛使用的库所提供的方法。Guava和Apache Commons IO。它们相当方便,对常见的情况有效,但不能对dotfiles有效。而且,他们没有提供删除单个扩展或所有扩展的选项。
Finally, we built a method to cover all requirements.
最后,我们建立了一个涵盖所有要求的方法。
As always, the full source code of the article is available over on GitHub.
一如既往,该文章的完整源代码可在GitHub上获得。