在Java中,如何从字符串中删除文件扩展名?

196

在Java中,最有效的方式是什么来截取后缀,例如:

title part1.txt
title part2.html
=>
title part1
title part2

2
高效的代码是你所期望的,我希望没有与 CPU 相关的意思。 - mkoryak
3
他并不是在问如何去做,他在问什么是最有效率的方式。我也是来这里寻找同样的答案的。 - Edward Falk
23个回答

317

7
对于95%的项目来说,这应该是可以接受的答案。像这样重写代码会导致许多头疼的问题! - Carsten Hoffmann
1
只需在gradle中添加以下行以添加依赖项:-compile 'commons-io:commons-io:2.6' - Deepak Sharma
17
如果你的项目中已经引入了Apache Commons I/O,那就没问题了。但如果你只需要其中的这部分功能,那么引入它至少会增加2.5MB的无用重量,而这个功能其实只需用一行代码就能轻松实现。 - foo
祝你好运,尝试在一行代码中完成它,以便即使在明显的边缘情况下也能成功。 - Steve Bosman
请注意,如果文件具有两个扩展名(例如filename.csv.zip),则此方法将无法正常工作。 - gzp___

258
str.substring(0, str.lastIndexOf('.'))

10
由于 str 没有被修改,所以应将此赋值给一个新变量。 - Nathan Feger
54
小心处理:如果文件名没有后缀,它会向你抛出一个异常。 - Andreas Dolk
24
归档.tar.bz2怎么样? - Anthony
26
str 包含小数点时,取出最后一个小数点前的字符串:if(str.contains(".")) str.substring(0, str.lastIndexOf('.')) - string.Empty
8
如果(str != null && str.contains(".")),则取出最后一个"."之前的子串:str.substring(0, str.lastIndexOf('.')). FilenameUtils是另一个依赖项,并不总是可用的。 - ocramot
显示剩余5条评论

94

使用String.substringString.lastIndexOf作为一行代码是不错的,但在处理某些文件路径时会出现问题。

以以下路径为例:

a.b/c

使用这个单行命令将会得到:

a

这是不正确的。

结果应该是c,但由于文件缺少扩展名,而路径中有一个带有.的目录,因此单行方法被欺骗为将路径的一部分作为文件名,这是不正确的。

需要进行检查

skaffman答案 的启发,我研究了FilenameUtils.removeExtension方法和Apache Commons IO

为了重新创建其行为,我编写了新方法应满足的一些测试,如下所示:

Path                  Filename
--------------        --------
a/b/c                 c
a/b/c.jpg             c
a/b/c.jpg.jpg         c.jpg
a.b/c c a.b/c.jpg c a.b/c.jpg.jpg c.jpg
c c c.jpg c c.jpg.jpg c.jpg

(这是我检查的全部内容——可能还有其他应该放置的检查我没考虑到。)

实现

以下是我编写的removeExtension方法的实现:

public static String removeExtension(String s) {

    String separator = System.getProperty("file.separator");
    String filename;

    // Remove the path upto the filename.
    int lastSeparatorIndex = s.lastIndexOf(separator);
    if (lastSeparatorIndex == -1) {
        filename = s;
    } else {
        filename = s.substring(lastSeparatorIndex + 1);
    }

    // Remove the extension.
    int extensionIndex = filename.lastIndexOf(".");
    if (extensionIndex == -1)
        return filename;

    return filename.substring(0, extensionIndex);
}

使用上述测试运行removeExtension方法会得到上面列出的结果。

该方法使用以下代码进行测试。由于是在Windows上运行,所以路径分隔符是\,在将其用作String字面值的一部分时必须使用\进行转义。

System.out.println(removeExtension("a\\b\\c"));
System.out.println(removeExtension("a\\b\\c.jpg"));
System.out.println(removeExtension("a\\b\\c.jpg.jpg"));

System.out.println(removeExtension("a.b\\c"));
System.out.println(removeExtension("a.b\\c.jpg"));
System.out.println(removeExtension("a.b\\c.jpg.jpg"));

System.out.println(removeExtension("c"));
System.out.println(removeExtension("c.jpg"));
System.out.println(removeExtension("c.jpg.jpg"));

结果如下:

c
c
c.jpg
c
c
c.jpg
c
c
c.jpg

结果是测试中所述的期望结果,该方法应满足这些期望结果。


4
非常好的回答。你使用 System.getProperty("file.separator") 而不是只用 File.separator,有特别的原因吗? - halirutan
2
警告一句:这个解决方案除了删除扩展名,还会删除前面的路径,不同于Apache Commons IO方法。 - DHa
3
看起来对于 /path/to/.htaccess 这个路径,它将会失败。 - Kuzeko

19

顺便说一下,在我的情况下,当我想要快速删除特定扩展名时,这大概是我所做的:

  if (filename.endsWith(ext))
    return filename.substring(0,filename.length() - ext.length());
  else
    return filename;

19
String foo = "title part1.txt";
foo = foo.substring(0, foo.lastIndexOf('.'));

4
不,可能会有多个“.”;你需要使用lastIndexOf('.')。 - Adam Jaskiewicz
你没有使用我认为你会用的方法,所以得分为-1。现在我的总得分是+0。快点改正吧! ;) - Michael Myers

11

你可以尝试这个函数,非常基础

public String getWithoutExtension(String fileFullPath){
    return fileFullPath.substring(0, fileFullPath.lastIndexOf('.'));
}

如果你有 c:\directory.old/filenoext 呢? - horvoje

10
如果您的项目已经依赖于Google核心库,请使用com.google.common.io.Files类中的方法。您需要使用的方法是getNameWithoutExtension

为什么有人反对我的答案? - Toby
请注意,此方法仅返回基本名称,因此路径也将被删除:https://google.github.io/guava/releases/19.0/api/docs/com/google/common/io/Files.html#getNameWithoutExtension(java.lang.String) - thSoft

9
String fileName="foo.bar";
int dotIndex=fileName.lastIndexOf('.');
if(dotIndex>=0) { // to prevent exception if there is no dot
  fileName=fileName.substring(0,dotIndex);
}

这是一个恶作剧的问题吗? :p

目前我想不到更快的方法了。


一般情况下都可以工作,因为lastIndexOf('.')对于两种路径类型的处理方式完全相同。为什么不可以呢? - undefined
抱歉,这个问题假设有一个扩展,所以你是正确的。 - undefined

5
filename.substring(filename.lastIndexOf('.'), filename.length()).toLowerCase();

3
与所要求的相反,不需要传递长度,只需使用一个参数子字符串。 - user486646

5

我发现coolbird的回答特别有用。

但是我将最后的结果语句更改为:

if (extensionIndex == -1)
  return s;

return s.substring(0, lastSeparatorIndex+1) 
         + filename.substring(0, extensionIndex);

我希望返回完整的路径名。

因此,"C:\Users\mroh004.COM\Documents\Test\Test.xml" 变成
   "C:\Users\mroh004.COM\Documents\Test\Test" 而不是
   "Test"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接