java获取文件的mime type

本文介绍了在Java中获取文件MimeType的五种方法,包括使用Files.probeContentType、URLConnection.getContentType、MimeTypesFileTypeMap、jMimeMagic库及Apache Tika工具集。每种方法都有其适用场景和优缺点。

方法一

@Test
public void whenUsingJava7_thenSuccess() {
    Path path = new File("product.png").toPath();
    String mimeType = Files.probeContentType(path);
    assertEquals(mimeType, "image/png");
}

此方法需要java 7及以上。Files.probeContentType使用已经安装的FileTypeDetector实现类的probeContentType方法来解析获得文件的的Mime Type。
如果其中一个实现能够识别解析该文件则立即返回,如果不能则使用系统默认实现类来解析识别。对于使用系统默认实现可能导致的失败会由于系统的差异而不同。另外如果文件不存在或者文件没有后缀名也会导致失败。

目前测试基本文件类型都能够解析成功,附上Files.probeContentType源码

    public static String probeContentType(Path path)
        throws IOException
    {
        // try installed file type detectors
        for (FileTypeDetector detector: FileTypeDetectors.installeDetectors) {
            String result = detector.probeContentType(path);
            if (result != null)
                return result;
        }

        // fallback to default
        return FileTypeDetectors.defaultFileTypeDetector.probeContentType(path);
    }

方法二

  1. 我们可以使用URLConnection.getContentType()方法来获取Mine Type,但是这个方法的主要缺陷就是太慢了。
@Test
public void whenUsingGetContentType_thenSuccess(){
    File file = new File("product.png");
    URLConnection connection = file.toURL().openConnection();
    String mimeType = connection.getContentType();
 
    assertEquals(mimeType, "image/png");
}
  1. 我们还可以使用URLConnection.getContentType()方法来获取Mine Type。这个方法依赖于内部的FileNameMap类,通过文件扩展名来匹配MineType。同时也可以调用guessContentTypeFromStream()方法传入一个输入流,通过文件的前几个字符判断文件的MineType。
@Test
public void whenUsingGuessContentTypeFromName_thenSuccess(){
    File file = new File("product.png");
    String mimeType = URLConnection.guessContentTypeFromName(file.getName());
 
    assertEquals(mimeType, "image/png");
}
  1. 一个相对较快的方式是使用URLConnection.getFileNameMap()。这个方法先通过URLConnection获取其内置的所有Mine Type列表,之后通过文件名取得对应值。URLConnection内置的类型是有限,默认加载路径为JRE_HOME/lib/content-types.properties,可以设置content.types.user.table属性自定义拓展改该列表。
@Test
public void whenUsingGetFileNameMap_thenSuccess(){
    File file = new File("product.png");
    FileNameMap fileNameMap = URLConnection.getFileNameMap();
    String mimeType = fileNameMap.getContentTypeFor(file.getName());
 
    assertEquals(mimeType, "image/png");
}
System.setProperty("content.types.user.table","<path-to-file>");

第二点中的方法和第三点本质上是相同的,通过查看URLConnection.guessContentTypeFromName源码可知。

    public static String guessContentTypeFromName(String fname) {
        return getFileNameMap().getContentTypeFor(fname);
    }

方法三

MimeTypesFileTypeMap通过文件后缀获取Mie Type,这里的参数可以是文件名也可以是File对象。

@Test
public void whenUsingMimeTypesFileTypeMap_thenSuccess() {
    File file = new File("product.png");
    MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
    String mimeType = fileTypeMap.getContentType(file.getName());
 
    assertEquals(mimeType, "image/png");
}

MimeTypesFileTypeMap通过查找加载mime.types文件来进行类型解析,该类加载文件的顺序如下:

  1. MimeTypesFileTypeMap 类以编程方式添加的。
  2. USER.HOME目录下的mime.types文件。
  3. JAVA.HOME/lib/mime.types。
  4. 工程resources目录下 META-INF/mime.types。
  5. 工程resources目录META-INF/mimetypes.default(通常只有activation.jar 下面有)。

这里所说的加载顺序应该来自MimeTypesFileTypeMap类的构造方法中定义的,第一点中的以编程方式添加应该是下面的dbv.addElement((Object)null);行,window下反编译出来是null。如果找不到具体加载的哪个文件可以本地debug试试。

    public MimetypesFileTypeMap() {
        Vector dbv = new Vector(5);
        MimeTypeFile mf = null;
        dbv.addElement((Object)null);
        LogSupport.log("MimetypesFileTypeMap: load HOME");

        String system_mimetypes;
        try {
            system_mimetypes = System.getProperty("user.home");
            if (system_mimetypes != null) {
                String path = system_mimetypes + File.separator + ".mime.types";
                mf = this.loadFile(path);
                if (mf != null) {
                    dbv.addElement(mf);
                }
            }
        } catch (SecurityException var6) {
        }

        LogSupport.log("MimetypesFileTypeMap: load SYS");

        try {
            system_mimetypes = System.getProperty("java.home") + File.separator + "lib" + File.separator + "mime.types";
            mf = this.loadFile(system_mimetypes);
            if (mf != null) {
                dbv.addElement(mf);
            }
        } catch (SecurityException var5) {
        }

        LogSupport.log("MimetypesFileTypeMap: load JAR");
        this.loadAllResources(dbv, "META-INF/mime.types");
        LogSupport.log("MimetypesFileTypeMap: load DEF");
        mf = this.loadResource("/META-INF/mimetypes.default");
        if (mf != null) {
            dbv.addElement(mf);
        }

        this.DB = new MimeTypeFile[dbv.size()];
        dbv.copyInto(this.DB);
    }

mime.types定义样例如下:
type=application/octet-stream exts=bin
其他样例参考

方法四

jMimeMagic是一个限制性许的库,可以通过该库去获取Mine type。maven 依赖配置如下(版本可依据当前最新配置):

<dependency>
    <groupId>net.sf.jmimemagic</groupId>
    <artifactId>jmimemagic</artifactId>
    <version>0.1.5</version>
</dependency>

使用代码如下:

@Test    
public void whenUsingJmimeMagic_thenSuccess() {
    File file = new File("product.png");
    Magic magic = new Magic();
    MagicMatch match = magic.getMagicMatch(file, false);
 
    assertEquals(match.getMimeType(), "image/png");
}

该函数可以使用流数据,因此文件可以不存在。

这说的应该是getMagicMatch方法的重载函数,可以直接使用bye[],如果使用File作为参数文件是必须存在的。

方法五

Apache Tika是一个工具集,可检测并从各种文件中提取元数据和文本。
它具有丰富而强大的API,并带有tika-core,我们可以利用它来检测fi的MIME类型。
maven依赖配置如下:

<dependency>
    <groupId>org.apache.tika</groupId>
    <artifactId>tika-core</artifactId>
    <version>1.18</version>
</dependency>

java示例代码如下

@Test
public void whenUsingTika_thenSuccess() {
    File file = new File("product.png");
    Tika tika = new Tika();
    String mimeType = tika.detect(file);
 
    assertEquals(mimeType, "image/png");
}

The library relies on magic markers in the stream prefix, for type resolution.(这句没懂,大概意思应该是通过文件前面几个字符判断Mine Type)。

总结

在这篇文章中我们使用了好几种方式获取文件的Mine Type,除此之外我们也分析了几种方法。文章中使用的完整代码gitHub链接

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值