如何获取文件的媒体类型(MIME类型)?
如何获取文件的媒体类型(MIME类型)?
在使用Apache Tika时,你只需要三行代码:
File file = new File("/path/to/file"); Tika tika = new Tika(); System.out.println(tika.detect(file));
如果你有一个Groovy控制台,只需粘贴并运行以下代码来进行测试:
@Grab('org.apache.tika:tika-core:1.14') import org.apache.tika.Tika; def tika = new Tika() def file = new File("/path/to/file") println tika.detect(file)
请记住,Tika的API非常丰富,它可以解析“任何”类型的文件。截至tika-core 1.14版本,你可以使用以下方法:
String detect(byte[] prefix) String detect(byte[] prefix, String name) String detect(File file) String detect(InputStream stream) String detect(InputStream stream, Metadata metadata) String detect(InputStream stream, String name) String detect(Path path) String detect(String name) String detect(URL url)
请查看[官方文档](http://tika.apache.org/1.14/api/)获取更多信息。
关于Tika的一个不好的地方是依赖项过多,它使我的JAR文件增加了54MB的大小!
1.17版本是独立的,只有648KB。
如果你只想根据文件扩展名进行检测,而不是根据文件内容进行检测,你可以使用以下代码:
new Tika().detect(file.toPath())
文档中说仍然使用文档内容。我认为你指的是`new Tika().detect(file.getPath())`,它只会使用文件的扩展名进行检测。
如何获取文件的媒体类型(MIME类型)?
不幸的是,
mimeType = file.toURL().openConnection().getContentType();
不起作用,因为这种使用URL的方式会锁定文件,例如,无法删除文件。
然而,您可以使用以下方式:
mimeType= URLConnection.guessContentTypeFromName(file.getName());
还有以下方法,它不仅仅使用文件扩展名,还会查看内容,具有优势:
InputStream is = new BufferedInputStream(new FileInputStream(file)); mimeType = URLConnection.guessContentTypeFromStream(is); //...关闭流
然而,正如上面的注释所建议的那样,内置的mime类型表相当有限,例如不包括MSWord和PDF。因此,如果您想进行泛化,就需要超越内置的库,例如使用Mime-Util(这是一个很棒的库,同时使用文件扩展名和内容)。
完美的解决方案-对我帮助很大!将FileInputStream
包装成BufferedInputStream
是关键部分-否则guessContentTypeFromStream
将返回null
(传递的InputStream
实例应支持标记)。
然而,URLConnection
的内容类型识别能力非常有限。例如,它无法检测application/pdf
。
它可以检测到pdf文件。但它无法检测到办公文件,例如*.doc。
它之所以被锁定,是因为您没有关闭它的方法。断开URL连接将解锁它。
无论是guessContentTypeFromStream
还是guessContentTypeFromName
都无法识别例如mp4。
guessContentTypeFromName()
使用默认的$JAVA_HOME/lib/content-types.properties
文件。您可以通过更改系统属性System.setProperty("content.types.user.table","/lib/path/to/your/property/file");
来添加自己的扩展文件。
它无法检测.js和.css文件。是否有其他方法可以检测这些文件?
有关Mime-Util
的任何链接吗?我在github上找到了这个项目,但没有任何描述:(
guessContentTypeFromName
使用了synchronized FileNameMap getFileNameMap
,在多线程中祝你好运。
如何获取文件的媒体类型(MIME类型)?
在Java 7中,您现在可以使用Files.probeContentType(path)来实现。
这对我非常有帮助,因为mime-util网站似乎已经关闭,我无法确定该库是否正在维护!
这个方法运行良好,但是我没有找到一种方法来添加更多我理解的文件类型。例如,ISO镜像返回null,.zip归档文件以及ini配置文件也返回null。
.garriss给了我更多的积分,比我给出的任何其他答案都多!真疯狂,不是吗? 🙂
请注意,Files.probeContentType(Path)在几个操作系统上存在缺陷,许多错误报告已经提交。我在ubuntu上遇到了一个问题,软件在windows上失败了。似乎在windows上,Files.probeContentType(Path)总是返回null。这不是我的系统,所以我没有检查JRE或者windows的版本。它可能是windows 7或8,可能使用了oracle的java 7的JRE。
我在OS X 10.9上运行,对于.xml、.png和.xhtml文件,我得到了null。我不知道我是否做错了什么,但这似乎相当糟糕。
如果文件没有扩展名,我无法成功地让它工作。
在类似*nix的系统上,似乎默认的文件类型检测器只返回null,而且用户必须手动添加一个或多个检测器实现,这似乎并不是很简单。所以至少对于我所需要的用例来说,即将文件扩展名映射到mime类型的简单方法,这个解决方案不起作用。
这个方法的一个重要限制是文件必须存在于文件系统中。它不能用于流或者字节数组等。
更奇怪的是,我有两台windows 8.1的笔记本电脑,其中一台在调用zip文件时得到application/x-zip-compressed,而另一台得到null。完全不可靠:\.那么,假设我希望我的应用程序根据文件的编码方案进行切换(比如说我的应用程序接受XML和JSON配置),而文件只是叫做“configuration”(没有扩展名),最可靠的方法是确定该文件的类型,有点作弊和读取几个字节吗?
如果我去掉文件名的扩展名,这个方法就无法返回mime类型。例如,如果文件名是test.mp4,我将其改为“test”,这个方法就会返回null。而且我将电影扩展名改为png等,它将返回png mime类型。
如果文件缺少或错误的扩展名,这就是无用的。
基于Linux的实现似乎使用Linux /usr/bin/file,这是好的,除非有一个扩展名,否则它将不再深入查看,这是不好的。如果将XML文件重命名为.json,它会告诉您它是JSON。输入垃圾,输出垃圾。除非您对文件数据非常确定,否则您真的不想相信这种方法。
获得Path对象的方法是使用Paths.get(str)。
在Windows上,它只使用扩展名来确定文件类型。在Linux上,直到Java 8,它使用了一堆探测器:基于Gnome I/O、Gnome VFS和libmagic库的基于内容的探测器以及基于扩展名的探测器,通过/etc/mime.types实现。但是从Java 9开始,JDK中移除了所有基于内容的探测器(1,2),只剩下了基于扩展名的探测器用于Linux。所以如果您的文件没有扩展名,这个方法将始终返回null 🙁
JDK中的默认实现是通过文件扩展名进行探测,添加github.com/overview/mime-types作为依赖,它将通过SPI使用它,然后通过魔术数字进行探测。