【问题标题】:Remove filename extension in Java在 Java 中删除文件扩展名
【发布时间】:2010-08-10 13:06:44
【问题描述】:

(不包括任何外部库。)

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

一些示例和预期结果:

  • 文件夹>文件夹
  • hello.txt > 你好
  • read.me > 阅读
  • hello.bkp.txt > hello.bkp
  • 奇怪的..name > 奇怪的。
  • .hidden > .hidden

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

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

  • rare.folder/hello >rare.folder/hello

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

【问题讨论】:

  • 你可以根据'.'标记字符串
  • 我认为至少在上述两种情况下都失败了。
  • “.hidden”不应变成“隐藏”
  • 更重要的是,“.hidden.txt”呢
  • @nineside 应该是“.hidden”。

标签: java file-extension


【解决方案1】:

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

public static String removeExtension(字符串文件名)

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

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()...

【讨论】:

  • 我应该提到我不能包含外部库,但我会看一下common的io源代码。
  • 这个 Commons 库是我最终采用的方法。我编辑了 OP 的问题以包含此约束。
  • 我喜欢你的做法! :) 这对我来说很完美!谢谢!
【解决方案2】:

我将尝试使用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 对象,因此如果这些也是输入和输出,就会稍微清晰一些。

【讨论】:

  • 挑剔:如果您的输入是文件路径(如变量名所述),则此解决方案在某些情况下会失败。请参阅修改后的问题。
  • 啊,好点子。我已经修改了答案,以便在我们检测到不需要更改的所有情况下都返回输入字符串;如果我们确实返回了一个修改过的字符串,那么它的前缀是输入路径中的目录(如果有的话)。
  • 我认为这确实是我的一个更好看的版本。
  • 这行不通,因为final int lastPeriodPos = name.lastIndexOf('.', 1); 将从索引 1 开始搜索并向后搜索,因此它只会检查前两个字符。
  • @pistol 这是一个非常好的观点,我很惊讶以前没有人发现它。我现在已经修复了逻辑,简单地采用 . 的最后一个索引,没有任何界限 - 并且还接受 0 的结果(即第一个字符是一个句点)不需要修改。感谢您指出这一点。
【解决方案3】:

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

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 编辑器框中。此代码不适用于生产。它只是作为一个很好的第一次尝试示例,说明我将如何从文件名中删除扩展名。

【讨论】:

  • 您需要检查name.lastIndexOf('.') != -1,否则最后一次substring 调用将引发异常。正如 hgpc 所说,不对文件名做任何假设,这似乎是一个应该正确处理的案例。
  • 这在 weird..name 示例中也失败了。
  • 我解决了这个问题。我们可能都在同一时间看到了它。感谢您指出这一点。
  • @And 在这种情况下,我会假设 extn 是 .name' and weird。` 是文件的名称。
  • @sylvain 是正确的。如果没有找到,lastIndexOf 将抛出异常。
【解决方案4】:

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

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

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

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

如果你不知道你在处理什么样的文件名,把它们都像 Unix 一样对待会帮助你。

【讨论】:

  • 您应该显示代码而不是尝试用文字输入条件
【解决方案5】:
int p=name.lastIndexOf('.');
if (p>0)
  name=name.substring(0,p);

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

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

【讨论】:

  • 我假设您在这里只有文件名,即没有路径。我看到其他人提出了这个问题。要处理完整路径将需要另外几行代码。仍然没什么大不了的。
【解决方案6】:

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

【讨论】:

    【解决方案7】:

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

    杀掉隐藏文件和不杀掉隐藏文件:

    ^(.*)\..*$
    ^(..*)\..*$
    

    【讨论】:

      【解决方案8】:

      使用 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
      

      Remover.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);
          }
      }
      

      【讨论】:

      • 在这个新案例中失败:rare.folder/hello > 稀有.folder/hello
      【解决方案9】:
      filename.replace("$(.+)\.\\w+", "\1");
      

      【讨论】:

        【解决方案10】:

        上面的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 );
        }
        

        【讨论】:

          猜你喜欢
          • 2012-06-29
          • 1970-01-01
          • 2012-05-12
          • 1970-01-01
          • 1970-01-01
          • 2013-03-14
          • 1970-01-01
          • 2019-01-03
          • 1970-01-01
          相关资源
          最近更新 更多