Java如何获取一个文件的MIME-TYPE

在介绍文件上传漏洞时,介绍了针对输入的文件需要判断:文件大小、文件扩展名、文件名称还有文件类型。其中关键的就是检测文件的内容的类型,如果避免一些不符合实际需求的内容上传就是其中最关键的,探测准确的内容类型,可以预防上传恶意代码或者恶意文件。

针对文件类型的获取,java提供了几种方法获取,本篇文章就概括起来介绍一下:

第一种方法,通过Files.probeContentType直接获取文件的类型,示例代码如下:

Path path = Files.createTempFile("myprofile", ".txt");
String mimeType = Files.probeContentType(path);

Files.probeContentType会使用系统安装的FileTypeDetector探测文件类型,如果没有安装的FileTypeDetector ,就是用系统默认的,相信信息在 Java如何判断一个上传文件的内容类型 有具体介绍。

缺点是:如果文件不再文件系统上存在或者文件没有扩展名,都不能成功获取文件的类型。

第二种方法,URLConnection

URLConnection提供了几个API来获取文件的MIME类型,主要由以下几个API:

1)API getContentType

示例代码如下:

	File myProcileFile = new File("myprofile.png");
    URLConnection connection = myProcileFile.toURL().openConnection();
    String mimeType = connection.getContentType();

这个APi获取文件类型的速度很慢。

2) guessContentTypeFromName

示例代码如下:

File myProcileFile = new File("myprofile.png");
		String mimeType = URLConnection.guessContentTypeFromName(myProcileFile.getName());

这个方法是通过FileNameMap通过扩展名来获取文件的MIME类型。

3) getFileNameMap

示例代码如下:

File myProcileFile = new File("myprofile.png");
		FileNameMap fileNameMap = URLConnection.getFileNameMap();
		String mimeType = fileNameMap.getContentTypeFor(myProcileFile.getName());

这种方法是根据一个MIME类型的表来获取文件类型的,内嵌的MIME类型是有限的,默认使用的是JRE_HOME/lib路径下的content-types.properties。当然,也可以通过自定义的表格来进行扩展。

System.setProperty("content.types.user.table","my-table-file");

第三种方法, MimeTypesFileTypeMap

示例代码如下:

File file = new File("myprofile.png");
    MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();
    String mimeType = mimetypesFileTypeMap.getContentType(file.getName());

MimeTypesFileTypeMap使用的是文件的扩展名获取文件类型。获取类型的参数既可以传递文件名也可以是File实例,传递文件实例,内部实现都一样,都是通过文件名来判断文件类型。获取文件类型的是通过获取一个文件mime.type的内容实现的,查找mime.type的顺序如下:

  1. 自定义的MimetypesFileTypeMap实例
  2. 用户home路径下的mime.types
  3. /lib/mime.types
  4. resources 路径下的META-INF/mime.types
  5. META-INF/mimetypes.default 命名的resource(经常在activation.jar 里)
  6. 如果以上都没有找到,就会直接返回application/octet-stream类型。

第四种方法, jMimeMagic

        jMimeMagic是一个可以用于获取mime类型的库,不过license比较严格,License的类型是GNU Library or Lesser General Public License version 2.0 (LGPLv2)。不过,根据https://mvnrepository.com/artifact/net.sf.jmimemagic/jmimemagic,目前依然停留在2017年的0.1.5版本,之后就再也没有更新,对于这种没有人维护的库,使用需谨慎。

实例代码如下:

File myProcileFile = new File("myprofile.png");
    Magic magic = new Magic();
    MagicMatch magicMatch = magic.getMagicMatch(myProcileFile, false);
	String mimeType =magicMatch.getMimeType();

也有方法可以接受stream参数,如果是stream,就可以不需要再本地文件系统有具体文件。

第五种方法,Apache Tika

Apache Tika是一个检测或者获取文件Meta数据的工具集,也提供了丰富的接口用于探测文件的MIME类型,他实现的基本原理也是根据stream里的Magic标示来实现的。如果不适用stream的接口,则是根据文件的扩展名来实现。具体说明和实例代码可以参考:Java如何判断一个上传文件的内容类型_java判断上传文件类型_jimmyleeee的博客-CSDN博客

总之,如果要获取文件内容类型的比较准确的话,可以使用Apache Tika和 jMimeMagic这种以识别文件内容里的Magic标识来实现的库。其他的API实际返回的MIME类型可能就不准确了,除非扩展自己的实现。

你可能感兴趣的:(web安全,java,开发语言)