如何获取Java文件的文件扩展名?


484

为了清楚起见,我不是在寻找MIME类型。

假设我输入以下内容: /path/to/file/foo.txt

我想要一种分解此输入的方法,特别.txt是扩展。在Java中是否有任何内置方法可以做到这一点?我想避免编写自己的解析器。


12
您永远不会知道何时会出现一些将扩展定义为以逗号分隔的新平台。现在,您需要编写平台相关的代码。Java框架应该更具前瞻性,并具有用于获取扩展的API,它们可以在其中编写与平台相关的代码,而您作为API的用户,请说获取扩展。
ArtOfWarfare 2013年

@ArtOfWarfare:天哪。让我们创建一个100MB的JRE拥有成千上万类,但请务必不要执行它返回的任何方法"txt""filename.txt"使用的,因为一些地方的平台可能需要"filename,txt"
埃里克·杜米尼尔

@EricDuminil“请确保不要实现任何从“ filename.txt”返回“ txt”的方法” 尝试path.substring(path.lastIndexOf("."));.....是的..他们一定不会重复复制某些内容...
VelocityPulse

@VelocityPulse这正是困扰我的地方。由于没有标准的方法来获取文件扩展名,因此您会得到许多错误的答案和稍有不同的实现。您的代码使用2个方法(我希望有一个单一的显式方法),它".txt"从返回"filename.txt",这可能不是期望的结果,最糟糕的是,StringIndexOutOfBoundsException如果没有扩展名,它将失败,而不是返回空字符串。
Eric Duminil

Answers:


649

在这种情况下,使用FilenameUtils.getExtensionApache的百科全书IO

这是一个使用方法的示例(您可以指定完整路径或仅指定文件名):

String ext1 = FilenameUtils.getExtension("/path/to/file/foo.txt"); // returns "txt"
String ext2 = FilenameUtils.getExtension("bar.exe"); // returns "exe"

Maven的依赖:

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.6</version>
</dependency>

Gradle Groovy DSL

implementation 'commons-io:commons-io:2.6'

Gradle Kotlin DSL

implementation("commons-io:commons-io:2.6")

其他https://search.maven.org/artifact/commons-io/commons-io/2.6/jar


70
应该注意的是,对于名为archive.tar.gz的文件,它仅返回“ gz”。
Zitrax 2014年

106
@Zitrax,因为“ gz”是文件扩展名。
BrainSlugs83 2015年

6
@ BrainSlugs83那么“焦油”是什么意思?
TuGordoBello '16

31
@zhelon .gz代表gnu压缩文件,而.tar代表(t)ape(ar)韭菜。因此,.tar.gz是gnu压缩文件中的tar文件,其扩展名为.gz。
cirovladimir

5
没有理由为此简单任务引入另一个库。
masterwok

311

您真的需要一个“解析器”吗?

String extension = "";

int i = fileName.lastIndexOf('.');
if (i > 0) {
    extension = fileName.substring(i+1);
}

假设您要处理的是类似Windows的简单文件名,而不是archive.tar.gz

顺便说一句,对于目录可能具有“。”但文件名本身没有的情况(如/path/to.a/file),您可以执行

String extension = "";

int i = fileName.lastIndexOf('.');
int p = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));

if (i > p) {
    extension = fileName.substring(i+1);
}

4
谢谢!如果您要执行的操作不仅仅是扩展名,那么肯定会需要一个解析器/对象……说,如果您只需要路径,父目录,文件名(减去扩展名)等。米C#和.NET,我们有这样的未来:msdn.microsoft.com/en-us/library/...
隆达

10
正如您所说,除了仅使用朴素的lastIndexOf(“。”)之外,还有很多事情需要考虑。我猜想Apache Commons为此提供了一种方法,该方法考虑了所有棘手的潜在问题。
MatrixFrog 2010年

12
我认为i > 0应更改为i >= 0i != -1。这样可以处理文件名,例如.htaccess
Pijusn

8
不管任何代码段多么简单……您仍然需要对其进行更新/维护/测试/使其作为方便的依赖项可用……如果已经有了所有这些库,则变得更加容易
Don Cheadle

2
在更多的陷阱上是文件是否以点结尾。更好的lib。如果(i> p && i <(fileName.length()-1)){扩展名= fileName.substring(i + 1);
tgkprog

97
private String getFileExtension(File file) {
    String name = file.getName();
    int lastIndexOf = name.lastIndexOf(".");
    if (lastIndexOf == -1) {
        return ""; // empty extension
    }
    return name.substring(lastIndexOf);
}

13
应该注意的是,这返回“。”。同样,因此您的文件扩展名将为“ .txt”,而不是其他一些答案中的“ txt”
NickEntin 2014年

2
更好的答案和@NickEntin更好的评论。删除句号“。” 从文件扩展名开始,可以编码为int lastIndexOf = name.lastIndexOf(“。”)+1;
Hanzallah Afgan'5

11
该方法在某些情况下可能不起作用,例如/usr/bin/foo.bar/httpconf
Iman Akbari

8
@ lukasz1985 1.数百个linux软件包使用“ init.d”之类的名称来创建目录,此外,依赖于没有带点目录的路径也不安全,因为它是非法的2.我在为Android编写代码,所以我使用了一些SDK方法我不记得了,但是我想stackoverflow.com/a/3571239/2546146没有这个缺陷
Iman Akbari

6
@Iman Akbari:getName()仅返回文件名本身,在您的示例中为“ httpconf”。
Dreamspace总裁

85

如果使用Guava库,则可以使用Files实用程序类。它具有特定的方法getFileExtension()。例如:

String path = "c:/path/to/file/foo.txt";
String ext = Files.getFileExtension(path);
System.out.println(ext); //prints txt

此外,您还可以使用类似的函数getNameWithoutExtension()获得文件名:

String filename = Files.getNameWithoutExtension(path);
System.out.println(filename); //prints foo

4
真?这是一个很棒的库,充满了实用程序。它们中的大多数将像强大的Guava Function一样是Java8的一部分。
JeanValjean 2013年

不幸的是,并非所有人都能决定使用哪个库。至少我们有Apache Commons,尽管它很旧。
路易斯·马丁内斯

1
如果您看到它的源代码,getFileExtension实际上int dotIndex = fileName.lastIndexOf('.'); return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1)没什么大不了的。另外,请注意Files由于某种原因将其标记为“不稳定”。
Al-Mothafar

@ Al-Mothafar很多类都被标记为不稳定类(请参阅多图生成器),我也不明白为什么:已经发布了几个类,但是在那里什么都没有改变。
JeanValjean

27

如果在Android上,则可以使用以下命令:

String ext = android.webkit.MimeTypeMap.getFileExtensionFromUrl(file.getName());

请注意,如果未对字符串进行编码(例如,包含空格或中文字符),则此方法将不起作用,请参阅:stackoverflow.com/a/14321470/1074998
Fruit

14

为了考虑点名没有字符的文件名,您必须使用已接受答案的稍微变化:

String extension = "";

int i = fileName.lastIndexOf('.');
if (i >= 0) {
    extension = fileName.substring(i+1);
}

"file.doc" => "doc"
"file.doc.gz" => "gz"
".doc" => "doc"

可能应该为“ foo”辩护。输入。
chrisinmtown

14

这是一种经过测试的方法

public static String getExtension(String fileName) {
    char ch;
    int len;
    if(fileName==null || 
            (len = fileName.length())==0 || 
            (ch = fileName.charAt(len-1))=='/' || ch=='\\' || //in the case of a directory
             ch=='.' ) //in the case of . or ..
        return "";
    int dotInd = fileName.lastIndexOf('.'),
        sepInd = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));
    if( dotInd<=sepInd )
        return "";
    else
        return fileName.substring(dotInd+1).toLowerCase();
}

和测试用例:

@Test
public void testGetExtension() {
    assertEquals("", getExtension("C"));
    assertEquals("ext", getExtension("C.ext"));
    assertEquals("ext", getExtension("A/B/C.ext"));
    assertEquals("", getExtension("A/B/C.ext/"));
    assertEquals("", getExtension("A/B/C.ext/.."));
    assertEquals("bin", getExtension("A/B/C.bin"));
    assertEquals("hidden", getExtension(".hidden"));
    assertEquals("dsstore", getExtension("/user/home/.dsstore"));
    assertEquals("", getExtension(".strange."));
    assertEquals("3", getExtension("1.2.3"));
    assertEquals("exe", getExtension("C:\\Program Files (x86)\\java\\bin\\javaw.exe"));
}

10

我很脏,可能使用String.replaceAll最小:

.replaceAll("^.*\\.(.*)$", "$1")

请注意,第一个*是贪婪的,因此它将尽可能地捕获尽可能多的字符,然后仅保留最后一个点和文件扩展名。


如果文件没有扩展名,此操作将失败。
Zack

是的,不幸的是,它仍然可以用于简单的情况,例如快速文件类型检测,以及扩展名不正确与扩展名没有太大区别,或者当替换结果等于输入时可以设置if条件。
Ebrahim Byagowi

1
甚至更短.replaceAll(".*\\.", "")
Ebrahim Byagowi

10
String path = "/Users/test/test.txt";
String extension = "";

if (path.contains("."))
     extension = path.substring(path.lastIndexOf("."));

返回“ .txt”

如果只需要“ txt”,请 path.lastIndexOf(".") + 1


9

从所有其他答案中可以明显看出,没有足够的“内置”功能。这是一种安全且简单的方法。

String getFileExtension(File file) {
    if (file == null) {
        return "";
    }
    String name = file.getName();
    int i = name.lastIndexOf('.');
    String ext = i > 0 ? name.substring(i + 1) : "";
    return ext;
}

7

怎么样(使用Java 1.5 RegEx):

    String[] split = fullFileName.split("\\.");
    String ext = split[split.length - 1];

6

如果您打算使用Apache commons-io,并且只想检查文件的扩展名然后进行一些操作,则可以使用代码,这是一个代码段:

if(FilenameUtils.isExtension(file.getName(),"java")) {
    someoperation();
}

请注意,根据文档,此检查区分大小写。
巴本·瓦尔丹扬

6

这是Java 8的另一种形式。

String ext = Arrays.stream(fileName.split("\\.")).reduce((a,b) -> b).orElse(null)

其工作方式如下:

  1. 使用“。”将字符串拆分为字符串数组。
  2. 将数组转换为流
  3. 使用reduce获取流的最后一个元素,即文件扩展名

4

JFileChooser怎么样?这并不简单,因为您将需要解析其最终输出...

JFileChooser filechooser = new JFileChooser();
File file = new File("your.txt");
System.out.println("the extension type:"+filechooser.getTypeDescription(file));

这是MIME类型...

好吧...我忘了你不想知道它的MIME类型。

以下链接中有趣的代码:http : //download.oracle.com/javase/tutorial/uiswing/components/filechooser.html

/*
 * Get the extension of a file.
 */  
public static String getExtension(File f) {
    String ext = null;
    String s = f.getName();
    int i = s.lastIndexOf('.');

    if (i > 0 &&  i < s.length() - 1) {
        ext = s.substring(i+1).toLowerCase();
    }
    return ext;
}

相关问题: 如何从Java中的字符串修剪文件扩展名?


4

这是一种.tar.gz即使在目录名称中带有点的路径中也能正确处理的方法:

private static final String getExtension(final String filename) {
  if (filename == null) return null;
  final String afterLastSlash = filename.substring(filename.lastIndexOf('/') + 1);
  final int afterLastBackslash = afterLastSlash.lastIndexOf('\\') + 1;
  final int dotIndex = afterLastSlash.indexOf('.', afterLastBackslash);
  return (dotIndex == -1) ? "" : afterLastSlash.substring(dotIndex + 1);
}

afterLastSlash创建afterLastBackslash它是为了使查找更快,因为如果其中包含一些斜杠,则不必搜索整个字符串。

char[]原来的内部String被重用,在那里没有添加任何垃圾,JVM可能会注意到这afterLastSlash是立即垃圾,以便将其放入堆栈而不是堆中


此方法是从Guava源代码复制而来的,您必须提及这一点。
2016年

1
我没有复制。如果它在Guava源代码中,则从此处复制它。也许通知他们。
奥拉西

抱歉,这并不完全相同,所以请问您和Guava开发人员的想法是否相同。
2016年

2
确实,“ gz”是返回的正确扩展名。如果调用代码也可以处理“ tar”,则应在getExtension函数外部另外进行检查。如果用户的文件名是,"my zip. don't touch.tar.gz"则此方法将返回错误的扩展名。
intrepidis

2
// Modified from EboMike's answer

String extension = "/path/to/file/foo.txt".substring("/path/to/file/foo.txt".lastIndexOf('.'));

扩展名在运行时应包含“ .txt”。


13
如果名称没有扩展名,将崩溃。
EboMike 2010年

2

这是带有Optional作为返回值的版本(因为您不能确定文件是否具有扩展名)...还可以进行完整性检查...

import java.io.File;
import java.util.Optional;

public class GetFileExtensionTool {

    public static Optional<String> getFileExtension(File file) {
        if (file == null) {
            throw new NullPointerException("file argument was null");
        }
        if (!file.isFile()) {
            throw new IllegalArgumentException("getFileExtension(File file)"
                    + " called on File object that wasn't an actual file"
                    + " (perhaps a directory or device?). file had path: "
                    + file.getAbsolutePath());
        }
        String fileName = file.getName();
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            return Optional.of(fileName.substring(i + 1));
        } else {
            return Optional.empty();
        }
    }
}

2

REGEX版本如何:

static final Pattern PATTERN = Pattern.compile("(.*)\\.(.*)");

Matcher m = PATTERN.matcher(path);
if (m.find()) {
    System.out.println("File path/name: " + m.group(1));
    System.out.println("Extention: " + m.group(2));
}

或支持空扩展名:

static final Pattern PATTERN =
    Pattern.compile("((.*\\" + File.separator + ")?(.*)(\\.(.*)))|(.*\\" + File.separator + ")?(.*)");

class Separated {
    String path, name, ext;
}

Separated parsePath(String path) {
    Separated res = new Separated();
    Matcher m = PATTERN.matcher(path);
    if (m.find()) {
        if (m.group(1) != null) {
            res.path = m.group(2);
            res.name = m.group(3);
            res.ext = m.group(5);
        } else {
            res.path = m.group(6);
            res.name = m.group(7);
        }
    }
    return res;
}


Separated sp = parsePath("/root/docs/readme.txt");
System.out.println("path: " + sp.path);
System.out.println("name: " + sp.name);
System.out.println("Extention: " + sp.ext);

* nix的结果:
路径:/ root / docs /
名称:自述文件
扩展名:txt

对于Windows,parsePath(“ c:\ windows \ readme.txt”):
路径:c:\ windows \
名称:自述文件
扩展名:txt



1

在这里,我做了一个小方法(但是不是那么安全,也不会检查很多错误),但是如果只有您在编写通用的Java程序,这足以找到文件类型。这不适用于复杂的文件类型,但是通常不会使用太多。

    public static String getFileType(String path){
       String fileType = null;
       fileType = path.substring(path.indexOf('.',path.lastIndexOf('/'))+1).toUpperCase();
       return fileType;
}

OP正在寻找内置的方法

(1)您应该使用适当的lastIndexOf文件名john.smith.report.doc。(2)您应该正确处理没有扩展名的情况。此方法返回ABC/XYZ类似的路径abc/xyz,这没有任何意义。返回""或更有意义null。(3)文件分隔符并不总是/
Radiodef '18年

1

从文件名获取文件扩展名

/**
 * The extension separator character.
 */
private static final char EXTENSION_SEPARATOR = '.';

/**
 * The Unix separator character.
 */
private static final char UNIX_SEPARATOR = '/';

/**
 * The Windows separator character.
 */
private static final char WINDOWS_SEPARATOR = '\\';

/**
 * The system separator character.
 */
private static final char SYSTEM_SEPARATOR = File.separatorChar;

/**
 * Gets the extension of a filename.
 * <p>
 * This method returns the textual part of the filename after the last dot.
 * There must be no directory separator after the dot.
 * <pre>
 * foo.txt      --> "txt"
 * a/b/c.jpg    --> "jpg"
 * a/b.txt/c    --> ""
 * a/b/c        --> ""
 * </pre>
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename the filename to retrieve the extension of.
 * @return the extension of the file or an empty string if none exists.
 */
public static String getExtension(String filename) {
    if (filename == null) {
        return null;
    }
    int index = indexOfExtension(filename);
    if (index == -1) {
        return "";
    } else {
        return filename.substring(index + 1);
    }
}

/**
 * Returns the index of the last extension separator character, which is a dot.
 * <p>
 * This method also checks that there is no directory separator after the last dot.
 * To do this it uses {@link #indexOfLastSeparator(String)} which will
 * handle a file in either Unix or Windows format.
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename  the filename to find the last path separator in, null returns -1
 * @return the index of the last separator character, or -1 if there
 * is no such character
 */
public static int indexOfExtension(String filename) {
    if (filename == null) {
        return -1;
    }
    int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
    int lastSeparator = indexOfLastSeparator(filename);
    return (lastSeparator > extensionPos ? -1 : extensionPos);
}

/**
 * Returns the index of the last directory separator character.
 * <p>
 * This method will handle a file in either Unix or Windows format.
 * The position of the last forward or backslash is returned.
 * <p>
 * The output will be the same irrespective of the machine that the code is running on.
 *
 * @param filename  the filename to find the last path separator in, null returns -1
 * @return the index of the last separator character, or -1 if there
 * is no such character
 */
public static int indexOfLastSeparator(String filename) {
    if (filename == null) {
        return -1;
    }
    int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR);
    int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR);
    return Math.max(lastUnixPos, lastWindowsPos);
}

学分

  1. 从Apache FileNameUtils类-http://grepcode.com/file/repo1.maven.org/maven2/commons-io/commons-io/1.3.2/org/apache/commons/io/FilenameUtils.java#FilenameUtils复制。 getExtension%28java.lang.String%29

1

在不使用任何库的情况下,可以按如下方式使用String方法拆分:

        String[] splits = fileNames.get(i).split("\\.");

        String extension = "";

        if(splits.length >= 2)
        {
            extension = splits[splits.length-1];
        }

0

只是基于正则表达式的选择。没有那么快,没有那么好。

Pattern pattern = Pattern.compile("\\.([^.]*)$");
Matcher matcher = pattern.matcher(fileName);

if (matcher.find()) {
    String ext = matcher.group(1);
}

0

我发现通过混合以上所有答案找到扩展的更好方法

public static String getFileExtension(String fileLink) {

        String extension;
        Uri uri = Uri.parse(fileLink);
        String scheme = uri.getScheme();
        if (scheme != null && scheme.equals(ContentResolver.SCHEME_CONTENT)) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            extension = mime.getExtensionFromMimeType(CoreApp.getInstance().getContentResolver().getType(uri));
        } else {
            extension = MimeTypeMap.getFileExtensionFromUrl(fileLink);
        }

        return extension;
    }

public static String getMimeType(String fileLink) {
        String type = CoreApp.getInstance().getContentResolver().getType(Uri.parse(fileLink));
        if (!TextUtils.isEmpty(type)) return type;
        MimeTypeMap mime = MimeTypeMap.getSingleton();
        return mime.getMimeTypeFromExtension(FileChooserUtil.getFileExtension(fileLink));
    }

0

我喜欢Spectre答案的简单性,在他的评论中,一个链接是指向另一个答案的链接,该链接在EboMike提出的另一个问题上修复了文件路径中的点。

我建议您在不实现某种第三方API的情况下:

private String getFileExtension(File file) {

    String name = file.getName().substring(Math.max(file.getName().lastIndexOf('/'),
            file.getName().lastIndexOf('\\')) < 0 ? 0 : Math.max(file.getName().lastIndexOf('/'),
            file.getName().lastIndexOf('\\')));
    int lastIndexOf = name.lastIndexOf(".");
    if (lastIndexOf == -1) {
        return ""; // empty extension
    }
    return name.substring(lastIndexOf + 1); // doesn't return "." with extension
}

像这样的事情在ImageIO的任何write方法中都很有用,在该方法中必须传递文件格式。

为什么可以自己动手使用整个第三方API?


0

这个特殊的问题给我带来了很多麻烦,然后我在这里找到了一个非常简单的解决方案。

file.getName().toLowerCase().endsWith(".txt");

而已。


3
OP需要一种提取扩展名的方法-无需测试。
Predrag Manojlovic

实际上,无论您在开发哪种情况,在大多数情况下,您都只需要处理特定类型的文件即可。因此,如果您的问题出在该领域,这将对您有所帮助。
Vikram Bhardwaj

4
这不能满足他的要求
Predrag Manojlovic

2
这不是问题的答案,但这确实是我想要的。
Ediolot

-1

尝试这个。

String[] extension = "adadad.adad.adnandad.jpg".split("\\.(?=[^\\.]+$)"); // ['adadad.adad.adnandad','jpg']
extension[1] // jpg

-1
  @Test
    public void getFileExtension(String fileName){
      String extension = null;
      List<String> list = new ArrayList<>();
      do{
          extension =  FilenameUtils.getExtension(fileName);
          if(extension==null){
              break;
          }
          if(!extension.isEmpty()){
              list.add("."+extension);
          }
          fileName = FilenameUtils.getBaseName(fileName);
      }while (!extension.isEmpty());
      Collections.reverse(list);
      System.out.println(list.toString());
    }

-4

Java在java.nio.file.Files类中具有内置的处理方式,可以满足您的需要:

File f = new File("/path/to/file/foo.txt");
String ext = Files.probeContentType(f.toPath());
if(ext.equalsIgnoreCase("txt")) do whatever;

请注意,此静态方法使用此处找到的规范来检索“内容类型”,该内容可能有所不同。


28
这是不正确的。probeContentType的返回类型是Mime内容类型,而不是文件扩展名。它通常不匹配扩展名。在文件浏览器中,这也会非常慢,因为它实际上会打开文件以确定类型。
查尔斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.