如何从URI中确定文件的扩展名

38
8个回答

80

首先,我想确保您知道无法找出URI链接到哪种类型的文件,因为以.jpg结尾的链接可能会让您访问.exe文件(这对于URL来说特别正确,因为符号链接和.htaccess文件),因此,如果您想限制允许的文件类型,从URI获取真实扩展名不是一个非常可靠的解决方案,当然,如果这是您想要的话。所以,我假设您只是想根据URI知道文件有什么扩展名,即使这并不完全可靠;

您可以使用下面的方法从任何URI、URL或文件路径中获取扩展名。您不需要使用任何库或扩展程序,因为这是基本的Java功能。该解决方案获取URI字符串中最后一个.(句点)符号的位置,并创建一个子字符串,从句点符号的位置开始,一直到URI字符串的末尾。

String uri = "http://www.google.com/support/enterprise/static/gsa/docs/admin/70/gsa_doc_set/integrating_apps/images/google_logo.png";
String extension = uri.substring(uri.lastIndexOf("."));

以下代码示例将输出URI中.png扩展名到extension变量中,请注意扩展名中包括一个.(句号)。如果您想获取没有前缀句号的文件扩展名,请将子字符串索引增加1,如下所示:

String extension = uri.substring(url.lastIndexOf(".") + 1);

使用这种方法的优点之一是相对于许多人使用的正则表达式方法,它消耗更少的资源、执行起来更加轻便,而且可以获得同样的结果。

此外,如果你想确保URL包含句点字符,请使用以下代码:

String uri = "http://www.google.com/support/enterprise/static/gsa/docs/admin/70/gsa_doc_set/integrating_apps/images/google_logo.png";
if(uri.contains(".")) {
    String extension = uri.substring(url.lastIndexOf("."));
}

你可能想进一步提高功能性以创建一个更加健壮的系统。两个例子可以是:

  • 通过检查URI是否存在或者确保URI的语法有效(可能使用正则表达式)来验证URI。
  • 修剪扩展名以去除不需要的空格。

我不会在这里讨论这两个特性的解决方案,因为这不是首要问题。

希望这可以帮到你!


25
如果URL在文件名之后有问号或井号,则这种方法不起作用。 - Albert Hendriks
3
你添加的句点检查并没有什么实际用处,因为顶级域名前面本来就有一个句点。 - Alex A.
如果URI中不包含句点字符,我可以假设该URI不是文件的URI吗? - Android Developer
@Android开发者,不是这样的。以以下URL为例:https://fluttercommunity.dev/_github/header/flutter_webview_plugin。 - ThinkDigital
Uri与Url不同。 - Ali Rezaiyan

22

这个链接可能会对那些仍然遇到问题的人有所帮助: 如何通过Uri获取文件的MIME类型?

 public static String getMimeType(Context context, Uri uri) {
    String extension;

    //Check uri format to avoid null
    if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
        //If scheme is a content
        final MimeTypeMap mime = MimeTypeMap.getSingleton();
        extension = mime.getExtensionFromMimeType(context.getContentResolver().getType(uri));
    } else {
        //If scheme is a File
        //This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
        extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());

    }

    return extension;
}

18

对此有两个答案。

如果一个URI没有“文件扩展名”,那么你无法通过从文本上观察它或将其转换为File来推断出它的扩展名。一般来说,URI和文件都不需要有扩展名。扩展名只是文件命名的惯例。

实际上,你想要的是文件的媒体类型/MIME类型/内容类型。你可以通过类似以下方法来确定媒体类型:

URLConnection conn = url.connect();
String type = conn.getContentType();
然而,如果服务器在响应中没有设置内容类型,getContentType()方法将返回null。(或者它可能会给你错误的内容类型或非特定的内容类型。)此时,您需要采用内容类型“猜测”,但我不知道在这种情况下是否会给您一个特定的类型。
但是,如果你“知道”该文件应该是OWL格式,为什么不把它的扩展名改成“.owl”呢?

1
如果没有网络,这将失败。 - Obaidah
是的。但如果没有网络,你就无法获取文件。所以它的类型几乎无关紧要。(如果你真的需要立即“知道”,你可以等待网络恢复或根据扩展名猜测。) - Stephen C
也许你只需要知道文件的扩展名,而不必获取文件本身? - Obaidah
如果URI中没有扩展名,并且您无法获取文件或其元数据以查找文件类型,则没有解决方案……除了时间旅行、洞察力或其他一些玄学方法。 - Stephen C

6

URLConnection.guessContentTypeFromName(url)会像第一个答案中的那样返回mime类型。 也许你只是想要:

String extension = url.getPath().replaceFirst("^.*/[^/]*(\\.[^\\./]*|)$", "$1");

正则表达式消耗所有内容直到最后一个斜杠,然后一直到一个句点并返回扩展名,如".owl"或""。(如果没有错误的话)

URLConnection.guessContentTypeFromName(address) // 在我看来,(String address) 是最好的答案。 - Albert Hendriks

6

接受的答案对于包含'?'或'/'在扩展名后面的url是无用的。因此,为了删除这个额外的字符串, 您可以使用getLastPathSegment()方法。它只给你uri中的名称,然后您可以按以下方式获取扩展名:

String name = uri.getLastPathSegment();
//Here uri is your uri from which you want to get extension
String extension = name.substring(name.lastIndexOf("."));

上述代码会使扩展名带有“.”,如果想要去掉这个点,可以按照以下代码进行编写:

String extension = name.substring(name.lastIndexOf(".") + 1);

嘿,Tedinoz,你有没有注意到Tim Visee的回答中的评论?如果URL在文件名后面有“?”或“/”,这将无法正常工作。如果您从Firebase获取图像的URL,则会在“。”(点)之后给出整个字符串。例如,如果URL为“https://firebasestorage.googleapis.com/v0/b/mememaker-13a8c.appspot.com/o/A_Letter_For%20_You.jpg?alt=media&token=e89f415c-8338-4e56-9d4c-9a87b6e0edb5”,则它会将扩展名作为“.jpg?alt=media&token=e89f415c-8338-4e56-9d4c-9a87b6e0edb5”给出,但我只想要“.jpg”作为扩展名。 - Nevil Ghelani

4

除了已接受的答案中提到的方法外,还有另一种有用的方式。如果您有一个远程URL,则可以使用URLConnection从中获取mimeType,例如:

  URLConnection urlConnection = new URL("http://www.google.com").openConnection();
  String mimeType = urlConnection.getContentType(); 

现在要从MimeType获取文件扩展名,我将参考这个文章


3

正如其他答案所解释的那样,如果没有检查文件,您无法真正了解内容类型。但是,您可以从URL预测文件类型。

Java 几乎 作为URL类的一部分提供了此功能。方法URL :: getFile将智能地获取URL的文件部分:

final URL url = new URL("http://www.example.com/a/b/c/stuff.zip?u=1");
final String file = url.getFile(); // file = "/a/b/c/stuff.zip?u=1"

我们可以使用这个来编写我们的实现:
public static Optional<String> getFileExtension(final URL url) {

    Objects.requireNonNull(url, "url is null");

    final String file = url.getFile();

    if (file.contains(".")) {

        final String sub = file.substring(file.lastIndexOf('.') + 1);

        if (sub.length() == 0) {
            return Optional.empty();
        }

        if (sub.contains("?")) {
            return Optional.of(sub.substring(0, sub.indexOf('?')));
        }

        return Optional.of(sub);
    }

    return Optional.empty();
}

这个实现应该能够正确地处理边缘情况:

assertEquals(
    Optional.of("zip"), 
    getFileExtension(new URL("http://www.example.com/stuff.zip")));

assertEquals(
    Optional.of("zip"), 
    getFileExtension(new URL("http://www.example.com/stuff.zip")));

assertEquals(
    Optional.of("zip"), 
    getFileExtension(new URL("http://www.example.com/a/b/c/stuff.zip")));

assertEquals(
    Optional.empty(), 
    getFileExtension(new URL("http://www.example.com")));

assertEquals(
    Optional.empty(), 
    getFileExtension(new URL("http://www.example.com/")));

assertEquals(
    Optional.empty(), 
    getFileExtension(new URL("http://www.example.com/.")));

-1

我是用这种方式来做的。

你可以使用更多的验证来检查任何文件扩展名:

String stringUri = uri.toString();
String fileFormat = "png";

                    if (stringUri.contains(".") && fileFormat.equalsIgnoreCase(stringUri.substring(stringUri.lastIndexOf(".") + 1))) {

                        // do anything

                    } else {

                        // invalid file

                    }

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