24

(不包括任何外部库。)

在不假设任何文件名的情况下,在 Java 中删除文件名扩展名的最有效方法是什么?

一些示例和预期结果:

  • 文件夹 > 文件夹
  • 你好.txt > 你好
  • read.me > 阅读
  • 你好.bkp.txt > 你好.bkp
  • 奇怪..名称>奇怪。
  • .hidden > .hidden

(或者最后一个应该隐藏起来?)

编辑:原始问题假设输入是文件名(不是文件路径)。由于一些答案是关于文件路径的,因此这些功能也应该在以下情况下工作:

  • 稀有的文件夹/你好 > 稀有的文件夹/你好

Sylvain M 的回答很好地处理了这种特殊情况。

4

10 回答 10

28

使用来自 apache http://commons.apache.org/io/的通用 io

公共静态字符串删除扩展(字符串文件名)

仅供参考,源代码在这里:

http://commons.apache.org/proper/commons-io/javadocs/api-release/src-html/org/apache/commons/io/FilenameUtils.html#line.1025

Arg,我刚刚尝试了一些东西......

System.out.println(FilenameUtils.getExtension(".polop")); // polop
System.out.println(FilenameUtils.removeExtension(".polop")); // empty string

所以,这个解决方案似乎不是很好......即使使用普通的io,你也必须使用removeExtension()getExtension()indexOfExtension()......

于 2010-08-10T13:11:13.473 回答
14

我将尝试使用双参数版本的lastIndexOf来删除一些特殊情况检查代码,并希望使意图更具可读性。感谢 Justin ' jinguy ' Nelson提供了这种方法的基础:

public static String removeExtention(String filePath) {
    // These first few lines the same as Justin's
    File f = new File(filePath);

    // if it's a directory, don't remove the extention
    if (f.isDirectory()) return filePath;

    String name = f.getName();

    // Now we know it's a file - don't need to do any special hidden
    // checking or contains() checking because of:
    final int lastPeriodPos = name.lastIndexOf('.');
    if (lastPeriodPos <= 0)
    {
        // No period after first character - return name as it was passed in
        return filePath;
    }
    else
    {
        // Remove the last period and everything after it
        File renamed = new File(f.getParent(), name.substring(0, lastPeriodPos));
        return renamed.getPath();
    }
}

对我来说,这比特殊情况的隐藏文件和不包含点的文件更清楚。我对您的规范的理解也更清楚;类似“删除最后一个点及其后面的所有内容,假设它存在并且不是文件名的第一个字符”。

请注意,此示例还暗示将字符串作为输入和输出。由于大多数抽象都需要File对象,因此如果这些也是输入和输出,那将更加清晰。

于 2010-08-10T13:54:50.960 回答
12

这将采用文件路径,然后返回不带扩展名的文件的新名称。

public static String removeExtention(String filePath) {
    File f = new File(filePath);
    // if it's a directory, don't remove the extention
    if (fisDirectory()) return f.getName();
    String name = f.getName();
    // if it is a hidden file
    if (name.startsWith(".")) {
        // if there is no extn, do not rmove one...
        if (name.lastIndexOf('.') == name.indexOf('.')) return name;
    }
    // if there is no extention, don't do anything
    if (!name.contains(".") return name;
    // Otherwise, remove the last 'extension type thing'
    return name.substring(0, name.lastIndexOf('.'))
}

人们应该注意到这是写在我的上网本上的,在小小的 SO 编辑框中。此代码不适用于生产。它只是作为一个很好的第一次尝试示例,说明我将如何从文件名中删除扩展名。

于 2010-08-10T13:11:07.723 回答
2

假设您有一个有效的文件名,这实际上非常简单。

在 Windows 文件名中,点字符仅用于指定扩展名。所以去掉点和它之后的任何东西。

在类 unix 文件名中,如果点在最后一个分隔符 ('/') 之后并且在它和最后一个分隔符之间至少有一个字符(如果没有分隔符,则不是第一个字符),则表示扩展名。找到最后一个点,看看它是否满足条件,如果满足,去掉它和任何尾随字符。

在执行此操作之前验证文件名很重要,因为这个算法对无效文件名可能会做一些意想不到的事情并生成一个有效的文件名。因此,在 Windows 中,您可能需要检查点后是否没有反斜杠或冒号。

如果你不知道你在处理什么样的文件名,把它们都当作 Unix 来处理会帮助你。

于 2010-08-10T13:18:35.143 回答
2
int p=name.lastIndexOf('.');
if (p>0)
  name=name.substring(0,p);

我说“p>0”而不是“p>=0”,因为如果第一个字符是句号,我们可能不想删除整个名称,就像在你的“.hidden”示例中一样。

您是想实际更新磁盘上的文件名还是只是在内部操作它?

于 2010-08-10T13:36:04.473 回答
1

与可以想到的最简单方法相比,这些东西的正则表达式“足够快”但效率不高:从末尾扫描字符串并在第一个点处截断它(不包括在内)。在 Java 中,您可以使用 lastIndexOf 和 substring 来仅获取您感兴趣的部分。最初的点应被视为一种特殊情况,如果最后一次出现“。” 是在开头,应该返回整个字符串。

于 2010-08-10T13:12:57.910 回答
1

我知道一个正则表达式来做到这一点,但是在 Java 中我是否必须编写 10 行代码才能进行简单的正则表达式替换?

有和没有杀死隐藏文件:

^(.*)\..*$
^(..*)\..*$
于 2010-08-10T13:14:56.573 回答
1

使用 new Remover().remove(String),

jdb@Vigor14:/tmp/stackoverflow> javac Remover.java && java Remover
folder > folder
hello.txt > hello
read.me > read
hello.bkp.txt > hello.bkp
weird..name > weird.
.hidden > .hidden

卸妆.java,

import java.util.*;

public class Remover {

    public static void main(String [] args){
        Map<String, String> tests = new LinkedHashMap<String, String>();
        tests.put("folder", "folder");
        tests.put("hello.txt", "hello");
        tests.put("read.me", "read");
        tests.put("hello.bkp.txt", "hello.bkp");
        tests.put("weird..name", "weird.");
        tests.put(".hidden", ".hidden");

        Remover r = new Remover();
        for(String in: tests.keySet()){
            String actual = r.remove(in);
            log(in+" > " +actual);
            String expected = tests.get(in);
            if(!expected.equals(actual)){
                throw new RuntimeException();
            }
        }
    }

    private static void log(String s){
        System.out.println(s);
    }

    public String remove(String in){
        if(in == null) {
            return null;
        }
        int p = in.lastIndexOf(".");
        if(p <= 0){
            return in;
        }
        return in.substring(0, p);
    }
}
于 2010-08-10T13:33:09.117 回答
0
filename.replace("$(.+)\.\\w+", "\1");
于 2010-08-10T13:15:54.313 回答
0

上面的remove()函数应该被重写以支持测试用例,比如LOST.DIR/myfile.txt

    public static String removeExtension( String in )
{
    int p = in.lastIndexOf(".");
    if ( p < 0 )
        return in;

    int d = in.lastIndexOf( File.separator );

    if ( d < 0 && p == 0 )
        return in;

    if ( d >= 0 && d > p )
        return in;

    return in.substring( 0, p );
}
于 2011-12-26T00:46:39.873 回答