从URL获取文件名

177
在Java中,如果给定一个形如http://www.example.com/some/path/to/a/file.xmljava.net.URL或字符串,最简单的方法是什么来获取文件名(不包括扩展名)?因此,在这个例子中,我需要返回"file"
我可以想到几种方法来解决这个问题,但我正在寻找一些易于阅读和简短的方法。

3
你知道末尾不一定需要文件名,甚至可能没有像文件名的东西。在这种情况下,服务器上可能有一个file.xml文件,也可能没有。 - Miserable Variable
2
在这种情况下,结果将是一个空字符串,或者可能为null。 - Sietse
3
我认为很清楚。如果URL指向一个文件,我对去掉扩展名(如果有)的文件名很感兴趣。查询部分不包括在文件名内。 - Sietse
4
文件名是URL中最后一个斜杠后面的部分。 文件扩展名是文件名中最后一个句点后面的部分。 - Sietse
1
相关链接:https://dev59.com/BG855IYBdhLWcg3w_5cQ(包含最佳答案,无依赖项,但不能实现去除扩展名的目标。) - Jason C
显示剩余4条评论
29个回答

227

不妨使用Apache commons-io,而非重新发明轮子:

import org.apache.commons.io.FilenameUtils;

public class FilenameUtilTest {

    public static void main(String[] args) throws Exception {
        URL url = new URL("http://www.example.com/some/path/to/a/file.xml?foo=bar#test");

        System.out.println(FilenameUtils.getBaseName(url.getPath())); // -> file
        System.out.println(FilenameUtils.getExtension(url.getPath())); // -> xml
        System.out.println(FilenameUtils.getName(url.getPath())); // -> file.xml
    }

}

2
在commons-io 2.2版本中,您仍然需要手动处理带有参数的URL。例如:"http://example.com/file.xml?date=2010-10-20" - Luke Quinane
18
FilenameUtils.getName(url)更适合。 - ehsun7b
4
似乎很奇怪在JDK中已经有易于使用的解决方案(参见URL#getPathString#substringPath#getFileNameFile#getName)时,还要添加对commons-io的依赖。 - Jason C
6
FilenameUtils 类旨在处理 Windows 和 *nix 路径,而不是 URL。 - nhahtdh
4
更新示例以使用URL,展示输出值的样本,并使用查询参数。 - Nick Grealy
显示剩余8条评论

211
String fileName = url.substring( url.lastIndexOf('/')+1, url.length() );

String fileNameWithoutExtn = fileName.substring(0, fileName.lastIndexOf('.'));

19
为什么被踩了?这不公平。我的代码是可行的,我在看到被踩后刚刚验证了我的代码。 - Real Red.
2
我给你点了个赞,因为它比我的版本稍微易读一些。下投票可能是因为在没有扩展名或文件的情况下它无法工作。 - Sietse
1
你可以省略 substring() 的第二个参数。 - Jon Onstott
13
这对于 http://example.org/file#anchorhttp://example.org/file?p=foo&q=barhttp://example.org/file.xml#/p=foo&q=bar 都不起作用。 - Matthias Ronge
3
如果你让String url = new URL(original_url).getPath(),并为不包含.的文件名添加一个特殊情况,那么这将正常工作。 - Jason C
显示剩余2条评论

45

如果您不需要删除文件扩展名,这里有一种方法可以在不使用容易出错的字符串操作和外部库的情况下完成。适用于Java 1.7+:

如果您不需要去除文件扩展名,这里有一种方法可以在不使用易出错的字符串操作和外部库的情况下完成。适用于Java 1.7+:

import java.net.URI
import java.nio.file.Paths

String url = "http://example.org/file?p=foo&q=bar"
String filename = Paths.get(new URI(url).getPath()).getFileName().toString()

1
@Carcigenicate 我刚刚再次测试了一下,似乎它能够正常工作。URI.getPath()返回一个String,所以我不明白为什么它不能工作。 - Zoltán
1
算了,我现在意识到我的问题是由于Clojure在Java交互期间如何处理var-args引起的。String重载不起作用,因为还需要传递一个空数组来处理Paths/get的var-args。如果你摆脱对getPath的调用,使用URI重载,它仍然可以工作。 - Carcigenicate
@Carcigenicate你是指Paths.get(new URI(url))吗?这对我似乎没有用。 - Zoltán
getFileName 需要 Android API 级别 26。 - Manuela

28

一句话概括:

new File(uri.getPath).getName

完整的代码(在Scala REPL中):

import java.io.File
import java.net.URI

val uri = new URI("http://example.org/file.txt?whatever")

new File(uri.getPath).getName
res18: String = file.txt

注意URI#gePath已经足够智能,可以剥离查询参数和协议方案。例如:

new URI("http://example.org/hey/file.txt?whatever").getPath
res20: String = /hey/file.txt

new URI("hdfs:///hey/file.txt").getPath
res21: String = /hey/file.txt

new URI("file:///hey/file.txt").getPath
res22: String = /hey/file.txt

2
好的解决方案! - CybeX
3
这是最佳选择,因为它仅使用标准JDK。 - Alexandros
3
最终,我只是选择了这个。优雅的解决方案。 - Yusuph wickama

26

这应该差不多就够了(错误处理部分就留给你了):

int slashIndex = url.lastIndexOf('/');
int dotIndex = url.lastIndexOf('.', slashIndex);
String filenameWithoutExtension;
if (dotIndex == -1) {
  filenameWithoutExtension = url.substring(slashIndex + 1);
} else {
  filenameWithoutExtension = url.substring(slashIndex + 1, dotIndex);
}

1
你需要考虑的一个错误处理方面是,如果你意外传递了一个没有文件名的URL(例如http://www.example.com/http://www.example.com/folder/),你将得到一个空字符串。 - rtpHarry
2
代码不起作用。lastIndexOf 不是这样使用的。但意图很明确。 - Robert
因为片段部分包含斜杠,而且在Apache Commons和Java自1.7以来有专门的函数可以实现此功能,所以被downvote了。 - Zoltán

14
public static String getFileName(URL extUrl) {
        //URL: "http://photosaaaaa.net/photos-ak-snc1/v315/224/13/659629384/s659629384_752969_4472.jpg"
        String filename = "";
        //PATH: /photos-ak-snc1/v315/224/13/659629384/s659629384_752969_4472.jpg
        String path = extUrl.getPath();
        //Checks for both forward and/or backslash 
        //NOTE:**While backslashes are not supported in URL's 
        //most browsers will autoreplace them with forward slashes
        //So technically if you're parsing an html page you could run into 
        //a backslash , so i'm accounting for them here;
        String[] pathContents = path.split("[\\\\/]");
        if(pathContents != null){
            int pathContentsLength = pathContents.length;
            System.out.println("Path Contents Length: " + pathContentsLength);
            for (int i = 0; i < pathContents.length; i++) {
                System.out.println("Path " + i + ": " + pathContents[i]);
            }
            //lastPart: s659629384_752969_4472.jpg
            String lastPart = pathContents[pathContentsLength-1];
            String[] lastPartContents = lastPart.split("\\.");
            if(lastPartContents != null && lastPartContents.length > 1){
                int lastPartContentLength = lastPartContents.length;
                System.out.println("Last Part Length: " + lastPartContentLength);
                //filenames can contain . , so we assume everything before
                //the last . is the name, everything after the last . is the 
                //extension
                String name = "";
                for (int i = 0; i < lastPartContentLength; i++) {
                    System.out.println("Last Part " + i + ": "+ lastPartContents[i]);
                    if(i < (lastPartContents.length -1)){
                        name += lastPartContents[i] ;
                        if(i < (lastPartContentLength -2)){
                            name += ".";
                        }
                    }
                }
                String extension = lastPartContents[lastPartContentLength -1];
                filename = name + "." +extension;
                System.out.println("Name: " + name);
                System.out.println("Extension: " + extension);
                System.out.println("Filename: " + filename);
            }
        }
        return filename;
    }

14

仅需3行代码,即可分别获取带扩展名的文件名、不带扩展名的文件名以及仅扩展名:

String urlStr = "http://www.example.com/yourpath/foler/test.png";

String fileName = urlStr.substring(urlStr.lastIndexOf('/')+1, urlStr.length());
String fileNameWithoutExtension = fileName.substring(0, fileName.lastIndexOf('.'));
String fileExtension = urlStr.substring(urlStr.lastIndexOf("."));

Log.i("File Name", fileName);
Log.i("File Name Without Extension", fileNameWithoutExtension);
Log.i("File Extension", fileExtension);

日志结果:

File Name(13656): test.png
File Name Without Extension(13656): test
File Extension(13656): .png

希望能对你有所帮助。


12

以下是几种方法:

Java 7 文件 I/O:

String fileName = Paths.get(strUrl).getFileName().toString();

Apache Commons:

String fileName = FilenameUtils.getName(strUrl);

使用Jersey:

UriBuilder buildURI = UriBuilder.fromUri(strUrl);
URI uri = buildURI.build();
String fileName = Paths.get(uri.getPath()).getFileName();

子字符串:

String fileName = strUrl.substring(strUrl.lastIndexOf('/') + 1);

1
很遗憾,你的 Java 7 文件 I/O 解决方案对我不起作用。我得到了一个异常。我用这个成功了:`Paths.get(new URL(strUrl).getFile()).getFileName().toString();`谢谢你的建议! - Sergey Nemchinov

9
String fileName = url.substring(url.lastIndexOf('/') + 1);

如果查询字符串包含“/”(相信我,它可能会包含),则无法正常工作。 - maaw
@maaw,请分享一个例子。 - Yogesh Rathi
https://host.com:9021/path/2721/filename.txt?X-Amz-Credential=n-it-cloud/20201214/standard/s3/aws4_request - maaw
然后您可以为单独的查询添加额外的检查。 - Yogesh Rathi

9
我想到了这个:

我有一个想法:

String url = "http://www.example.com/some/path/to/a/file.xml";
String file = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.'));

或者在没有文件,只有路径的URL上。 - Sietse
你的代码也是正确的。反正我们本来就不应该检查负面条件。给你点赞。顺便问一下,Dirk Kuyt 这个名字听起来熟悉吗? - Real Red.

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