如何在python中找到文件的mime类型?
Posted
技术标签:
【中文标题】如何在python中找到文件的mime类型?【英文标题】:How to find the mime type of a file in python? 【发布时间】:2010-09-07 19:11:06 【问题描述】:假设您想在某处保存一堆文件,例如在 BLOB 中。假设您想通过网页发送这些文件并让客户端自动打开正确的应用程序/查看器。
假设:浏览器通过 HTTP 响应中的 mime-type (content-type?) 标头确定要使用哪个应用程序/查看器。
基于该假设,除了文件的字节,您还希望保存 MIME 类型。
如何找到文件的 MIME 类型?我目前使用的是 Mac,但这也应该适用于 Windows。
将文件发布到网页时浏览器是否添加此信息?
是否有一个简洁的 python 库来查找这些信息? WebService 还是(甚至更好)可下载的数据库?
【问题讨论】:
【参考方案1】:标准库中的mimetypes module 将根据文件扩展名确定/猜测 MIME 类型。
如果用户正在上传文件,HTTP 帖子将在数据旁边包含文件的 MIME 类型。例如,Django 将此数据作为UploadedFile 对象的属性提供。
【讨论】:
如果文件存储在 BLOB 中,如问题中所述,您可能不知道文件扩展名。 文件扩展名不是确定 mime 类型的可靠方法。import mimetypes
mimetypes.MimeTypes().guess_type(filename)[0]
在 python 3.6 中有效:mimetypes.guess_type(path_file_to_upload)[1]
虽然@cerin 认为文件扩展名不可靠是对的,但我刚刚发现python-magic
的准确性(如最佳答案中所建议)甚至更低,正如@987654323 所证实的那样@。所以,mimetypes
似乎更适合我。【参考方案2】:
您没有说明您使用的是什么网络服务器,但 Apache 有一个名为 Mime Magic 的漂亮小模块,当被告知这样做时,它使用它来确定文件的类型。它读取文件的一些内容并尝试根据找到的字符来确定它是什么类型。而Dave Webb Mentioned MimeTypes Module 在 python 下也可以工作,前提是扩展很方便。
或者,如果您坐在 UNIX 机器上,您可以使用 sys.popen('file -i ' + fileName, mode='r')
来获取 MIME 类型。 Windows 应该有一个等效的命令,但我不确定它是什么。
【讨论】:
现在你可以做 subprocess.check_output(['file', '-b', '--mime', filename]) 当 python-magic 做同样的事情时,真的没有理由求助于使用外部工具,所有包装和舒适。【参考方案3】:在 python 2.6 中:
import shlex
import subprocess
mime = subprocess.Popen("/usr/bin/file --mime " + shlex.quote(PATH), shell=True, \
stdout=subprocess.PIPE).communicate()[0]
【讨论】:
这是不必要的,因为file
命令基本上只是 libmagic 的一个包装器。您也可以使用 python 绑定(python-magic),就像西蒙的回答一样。
这取决于操作系统。例如,在 Mac OS X 上,您有“文件”,但在正常环境中没有 libmagic。
这对我来说看起来不安全,应该转义 PATH。知道 Python 的等价物是什么,但 php 开发人员会使用 Popen("/usr/bin/file --mime ".escapeshellarg(PATH));
- 例如,您的代码在包含换行符或引号的文件上会失败,可能还有 $dollarsign,但它也可以保护您免受黑客的攻击 PATH='; rm -rfv /
和此类 shell 注入【参考方案4】:
比使用 mimetypes 库更可靠的方法是使用 python-magic 包。
import magic
m = magic.open(magic.MAGIC_MIME)
m.load()
m.file("/tmp/document.pdf")
这相当于使用 file(1)。
在 Django 上,还可以确保 MIME 类型与 UploadedFile.content_type 的匹配。
【讨论】:
查看 Simon Zimmermann 的帖子了解 python-magic 的更新使用 @DarenThomas:正如 mammadori 的回答中提到的,这个答案没有过时,并且与 Simon Zimmermann 的解决方案不同。如果您安装了文件实用程序,您可能可以使用此解决方案。它适用于我的 file-5.32。在 gentoo 上,您还必须为文件包启用 python USE-flag。【参考方案5】:toivotuo 建议的 python-magic 方法已过时。 Python-magic's 当前主干在 Github 上,根据那里的自述文件,找到 MIME 类型是这样完成的。
# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
【讨论】:
感谢您的评论!请注意,“以上”在 *** 中是一个困难的概念,因为排序是按投票分组的,并且在组内随机排序。我猜你指的是@toivotuo 的回答。 是的,在撰写此回复时,我没有足够的“积分”来创建 cmets。但我可能应该把它写成评论,这样@toivotuo 就可以编辑他的问题了。 rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL:darwinsys.com/file 摘要:libmagic API 的 Python 绑定 rpm -qf /usr/bin/文件 -i 名称:文件 URL:darwinsys.com/file python-magic 来自darwinsys.com/file,它与 Linux Fedora 一起使用,就像@toivotuo 所说的那样。而且似乎更主流。 请注意,debian/ubuntu 包名为 python-magic 与 pip 同名包不同。两者都是import magic
,但内容不兼容。请参阅***.com/a/16203777/3189 了解更多信息。
正如我评论 toivotuo 的答案,它并没有过时!你在谈论一个不同的图书馆。您能否在答案中删除或替换该陈述?目前很难找到最佳解决方案。【参考方案6】:
mimetypes 模块仅根据文件扩展名识别文件类型。如果您将尝试恢复没有扩展名的文件的文件类型,则 mimetypes 将不起作用。
【讨论】:
我认为这不是真的。 MIME 类型是关于如何告诉别人一种数据格式,而不是关于如何自己找出数据格式。如果您使用的工具仅根据扩展名猜测格式并打印出 MIME 类型,那么如果没有文件扩展名,您将无法使用该工具。但其他猜测格式的方法也是可能的,例如,通过解析器检查。【参考方案7】:有 3 个不同的库包装了 libmagic。
其中 2 个在 pypi 上可用(因此 pip install 将起作用):
文件魔法 蟒蛇魔法另外一个类似于 python-magic 的可以直接在最新的 libmagic 源中获得,它可能是你的 linux 发行版中的那个。
在 Debian 中,python-magic 包是关于这个的,它像 toivotuo 所说的那样被使用,它并没有像 Simon Zimmermann 所说的那样过时(恕我直言)。
在我看来,这是另一种看法(libmagic 的原作者)。
太糟糕了,不能直接在pypi上使用。
【讨论】:
为方便起见,我添加了一个 repo:github.com/mammadori/magic-python 这样你就可以:pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
【参考方案8】:
这似乎很容易
>>> from mimetypes import MimeTypes
>>> import urllib
>>> mime = MimeTypes()
>>> url = urllib.pathname2url('Upload.xml')
>>> mime_type = mime.guess_type(url)
>>> print mime_type
('application/xml', None)
请参考Old Post
更新 - python 3+版本,现在更方便了:
import mimetypes
print(mimetypes.guess_type("sample.html"))
【讨论】:
我认为您的示例中不需要 urllib。 对于 Python 3.X 将 import urllib 替换为 from urllib import request。然后使用“请求”而不是 urllib 也适用于 python 2.7 @oetzi 的solution 使用了这个模块,但是更简单。【参考方案9】:@toivotuo 的方法在 python3 下对我来说效果最好、最可靠。我的目标是识别没有可靠 .gz 扩展名的 gzip 压缩文件。我安装了python3-magic。
import magic
filename = "./datasets/test"
def file_mime_type(filename):
m = magic.open(magic.MAGIC_MIME)
m.load()
return(m.file(filename))
print(file_mime_type(filename))
对于 gzip 压缩文件,它返回: 应用程序/gzip;字符集=二进制
对于解压缩的 txt 文件(iostat 数据): 文本/纯文本; charset=us-ascii
对于 tar 文件: 应用程序/x-tar;字符集=二进制
对于 bz2 文件: 应用程序/x-bzip2;字符集=二进制
最后但并非最不重要的一个 .zip 文件: 应用程序/压缩包;字符集=二进制
【讨论】:
【参考方案10】:在 Python 3.x 和 webapp 中,文件的 url 不能有扩展名或假扩展名。你应该安装 python-magic,使用
pip3 install python-magic
对于 Mac OS X,您还应该使用安装 libmagic
brew install libmagic
代码sn-p
import urllib
import magic
from urllib.request import urlopen
url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.readline())
print(mime_type)
或者,您可以将大小放入读取中
import urllib
import magic
from urllib.request import urlopen
url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.read(128))
print(mime_type)
【讨论】:
会加载整个文件吗? 不,它是一个流,所以通常只有几个字节。 我已经通过 response.readline() 或 response.read(128) 编辑了谢谢!【参考方案11】:我尝试了很多示例,但使用 Django mutagen 效果很好。
检查文件是否为mp3
的示例
from mutagen.mp3 import MP3, HeaderNotFoundError
try:
audio = MP3(file)
except HeaderNotFoundError:
raise ValidationError('This file should be mp3')
缺点是您检查文件类型的能力有限,但如果您不仅要检查文件类型,还要访问其他信息,这是一个很好的方法。
【讨论】:
我还需要检查安全性【参考方案12】:2017 年更新
不用去 github,它在 PyPi 上用不同的名字:
pip3 install --user python-magic
# or:
sudo apt install python3-magic # Ubuntu distro package
代码也可以简化:
>>> import magic
>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
【讨论】:
你可以对js或css文件做同样的事情吗? 当然,为什么不呢??【参考方案13】:Python 绑定到 libmagic
关于这个主题的所有不同答案都非常令人困惑,所以我希望通过这个关于 libmagic 不同绑定的概述来更清楚一点。以前 mammadori 提供了一个 short answer 列出可用选项。
libmagic
模块名称:magic
pypi:file-magic
来源:https://github.com/file/file/tree/master/python
在确定文件 mime 类型时,选择的工具简称为 file
,其后端称为 libmagic
。 (参见Project home page。)该项目是在私有cvs-repository中开发的,但是有一个read-only git mirror on github。
现在,如果您想在 python 中使用任何 libmagic 绑定,您将需要这个工具,它已经附带了自己的 python 绑定,称为file-magic
。没有太多专门的文档,但您可以随时查看 c-library 的手册页:man libmagic
。基本用法在readme file中描述:
import magic
detected = magic.detect_from_filename('magic.py')
print 'Detected MIME type: '.format(detected.mime_type)
print 'Detected encoding: '.format(detected.encoding)
print 'Detected file type name: '.format(detected.name)
除此之外,您还可以通过使用magic.open(flags)
创建一个Magic
对象来使用该库,如example file 所示。
toivotuo 和 ewr2san 都使用 file
工具中包含的这些 file-magic
绑定。他们错误地认为,他们正在使用python-magic
包。 这似乎表明,如果同时安装了file
和python-magic
,则python 模块magic
指的是前者。
蟒蛇魔法
模块名称:magic
pypi:python-magic
来源:https://github.com/ahupp/python-magic
这是 Simon Zimmermann 在 his answer 中谈到的库,Claude COULOMBE 和 Gringo Suave 也使用它。
文件魔法
模块名称:magic
pypi:filemagic
来源:https://github.com/aliles/filemagic
注意:本项目最后一次更新是在 2013 年!
由于基于相同的c-api,该库与libmagic
中包含的file-magic
有一些相似之处。它仅由mammadori 提及,没有其他答案使用它。
【讨论】:
【参考方案14】:对于字节数组类型的数据,你可以使用 magic.from_buffer(_byte_array,mime=True)
【讨论】:
【参考方案15】:我首先尝试 mimetypes 库。如果它不起作用,我会改用 python-magic 库。
import mimetypes
def guess_type(filename, buffer=None):
mimetype, encoding = mimetypes.guess_type(filename)
if mimetype is None:
try:
import magic
if buffer:
mimetype = magic.from_buffer(buffer, mime=True)
else:
mimetype = magic.from_file(filename, mime=True)
except ImportError:
pass
return mimetype
【讨论】:
【参考方案16】:python 3 参考:https://docs.python.org/3.2/library/mimetypes.html
mimetypes.guess_type(url, strict=True) 根据文件类型猜测 在其文件名或 URL 上,由 url 给出。返回值是一个元组 (type, encoding) 如果无法猜到类型,则 type 为 None (缺少或未知的后缀)或“类型/子类型”形式的字符串, 可用于 MIME 内容类型标头。
encoding 是 None 表示没有编码或程序的名称用于 编码(例如压缩或 gzip)。该编码适合用作 Content-Encoding 标头,而不是 Content-Transfer-Encoding 标头。 映射是表驱动的。编码后缀区分大小写; 类型后缀首先区分大小写,然后区分大小写 不敏感。
可选的严格参数是一个标志,指定列表是否 已知的 MIME 类型仅限于注册的官方类型 伊安娜。当 strict 为 True(默认值)时,只有 IANA 类型是 支持的;当 strict 为 False 时,一些额外的非标准但 还可以识别常用的 MIME 类型。
import mimetypes
print(mimetypes.guess_type("sample.html"))
【讨论】:
【参考方案17】:我很惊讶没有人提到它,但 Pygments 能够对 mime 类型(尤其是文本文档)做出有根据的猜测。
Pygments 实际上是一个 Python 语法高亮库,但它有一种方法可以有根据地猜测您的文档是 500 种支持的文档类型中的哪一种。 即 c++ vs C# vs Python vs etc
import inspect
def _test(text: str):
from pygments.lexers import guess_lexer
lexer = guess_lexer(text)
mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
print(mimetype)
if __name__ == "__main__":
# Set the text to the actual defintion of _test(...) above
text = inspect.getsource(_test)
print('Text:')
print(text)
print()
print('Result:')
_test(text)
输出:
Text:
def _test(text: str):
from pygments.lexers import guess_lexer
lexer = guess_lexer(text)
mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
print(mimetype)
Result:
text/x-python
现在,它并不完美,但如果您需要能够分辨正在使用的 500 种文档格式中的哪一种,这非常有用。
【讨论】:
【参考方案18】:13 年后... 此页面上有关 python 3 的大多数答案要么已过时,要么不完整。 要获得我使用的 mime 类型:
import mimetypes
mt = mimetypes.guess_type("https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")
if mt:
print("Mime Type:", mt[0])
else:
print("Cannot determine Mime Type")
# Mime Type: application/pdf
Live Demo
来自Python docs:
mimetypes.guess_type
(url, strict=True)
根据 url 给出的文件名、路径或 URL 猜测文件的类型。 URL 可以是字符串或path-like object。
返回值是一个元组(type, encoding)
,其中type是None
如果类型不能被猜到(缺少或未知的后缀)或'type/subtype'
形式的字符串,可用对于 MIME content-type 标头。
encoding 是 None
,表示无编码或用于编码的程序的名称(例如 compress 或 gzip)。该编码适合用作 Content-Encoding 标头,不 适合用作 Content-Transfer-Encoding 标头。映射是表驱动的。编码后缀区分大小写;类型后缀首先尝试区分大小写,然后不区分大小写。
可选的 strict 参数是一个标志,指定已知 MIME 类型列表是否仅限于官方类型 registered with IANA。当 strict 为 True
(默认)时,仅支持 IANA 类型;当 strict 为 False
时,还会识别一些额外的非标准但常用的 MIME 类型。
在 3.8 版中更改:添加了对作为 path-like object 的 url 的支持。
【讨论】:
以上是关于如何在python中找到文件的mime类型?的主要内容,如果未能解决你的问题,请参考以下文章
使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型
使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型
使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型
使用 .NET,如何根据文件签名而不是扩展名找到文件的 mime 类型