假设您想在某处保存一堆文件,例如在 BLOB 中。假设您想通过网页发送这些文件并让客户端自动打开正确的应用程序/查看器。
假设:浏览器通过 HTTP 响应中的 mime-type (content-type?) 标头确定使用哪个应用程序/查看器。
基于该假设,除了文件的字节之外,您还希望保存 MIME 类型。
如何找到文件的 MIME 类型?我目前使用的是 Mac,但这也应该适用于 Windows。
将文件发布到网页时浏览器是否添加此信息?
是否有一个简洁的 python 库来查找这些信息? WebService 还是(甚至更好)可下载的数据库?
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'
标准库中的 mimetypes module 将根据文件扩展名确定/猜测 MIME 类型。
如果用户正在上传文件,HTTP 帖子将在数据旁边包含文件的 MIME 类型。例如,Django 将此数据作为 UploadedFile 对象的属性提供。
import mimetypes
mimetypes.MimeTypes().guess_type(filename)[0]
mimetypes.guess_type(path_file_to_upload)[1]
python-magic
的准确性(如最佳答案中所建议)甚至更低,正如 github.com/s3tools/s3cmd/issues/198 所证实的那样。所以,mimetypes
对我来说似乎是一个更好的候选人。
比使用 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 的匹配。
这似乎很容易
>>> 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"))
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
从 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 版更改: 添加了对 url 作为 path-like object 的支持。
Python 绑定到 libmagic
关于这个主题的所有不同答案都非常令人困惑,所以我希望通过这个对 libmagic 不同绑定的概述能够更清楚地说明。以前 mammadori 提供了一个 short answer 列出可用选项。
libmagic
模块名称:魔法
pypi:文件魔术
来源:https://github.com/file/file/tree/master/python
在确定文件 mime 类型时,选择的工具简称为 file
,其后端称为 libmagic
。 (请参阅 Project home page。)该项目是在私有 cvs-repository 中开发的,但有一个 read-only git mirror on github。
现在,如果您想在 python 中使用任何 libmagic 绑定,您将需要这个工具,它已经附带了自己的名为 file-magic
的 python 绑定。没有太多专门的文档,但您可以随时查看 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
指的是前者。
蟒蛇魔术
模块名称:魔法
pypi: 蟒蛇魔法
来源:https://github.com/ahupp/python-magic
这是 Simon Zimmermann 在 his answer 中谈到的库,它也被 Claude COULOMBE 和 Gringo Suave 使用。
文件魔术
模块名称:魔法
pypi:文件魔术
来源:https://github.com/aliles/filemagic
注意:此项目最后一次更新是在 2013 年!
由于基于相同的 c-api,该库与包含在 libmagic
中的 file-magic
有一些相似之处。它仅被 mammadori 提及,没有其他答案使用它。
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'
有 3 个不同的库包装了 libmagic。
其中 2 个在 pypi 上可用(因此 pip install 将起作用):
文件魔术
蟒蛇魔术
另一个类似于 python-magic 的,可以直接在最新的 libmagic 源中获得,它可能是你的 linux 发行版中的那个。
在 Debian 中,python-magic 包是关于这个的,它像 toivotuo 所说的那样被使用,它并没有像 Simon Zimmermann 所说的那样被淘汰(恕我直言)。
在我看来,另一种看法(由 libmagic 的原作者)。
太糟糕了不能直接在 pypi 上使用。
pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
在 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),就像西蒙的回答一样。
Popen("/usr/bin/file --mime ".escapeshellarg(PATH));
- 例如,您的代码在包含换行符或引号的文件上可能会失败,可能还有 $dollarsign,但它也可以保护您免受黑客执行 PATH='; rm -rfv /
和此类 shell 注入
您没有说明您使用的是什么网络服务器,但是 Apache 有一个名为 Mime Magic 的漂亮小模块,当被告知这样做时,它使用它来确定文件的类型。它读取文件的一些内容并尝试根据找到的字符来确定它是什么类型。并且作为 Dave Webb Mentioned,python 下的 MimeTypes Module 将起作用,前提是扩展很方便。
或者,如果您坐在 UNIX 机器上,您可以使用 sys.popen('file -i ' + fileName, mode='r')
来获取 MIME 类型。 Windows 应该有一个等效的命令,但我不确定它是什么。
@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 文件,它返回:application/gzip;字符集=二进制
对于解压缩的 txt 文件(iostat 数据):text/plain; charset=us-ascii
对于 tar 文件:application/x-tar;字符集=二进制
对于 bz2 文件:application/x-bzip2;字符集=二进制
最后但并非最不重要的一个 .zip 文件:application/zip;字符集=二进制
蟒蛇 3 参考:https://docs.python.org/3.2/library/mimetypes.html
mimetypes.guess_type(url, strict=True) 根据 url 给出的文件名或 URL 猜测文件的类型。返回值是一个元组(类型,编码),其中类型为 None 如果无法猜测类型(缺少或未知的后缀)或形式为“类型/子类型”的字符串,可用于 MIME 内容类型标头。 encoding 是 None 表示没有编码或用于编码的程序的名称(例如 compress 或 gzip)。编码适合用作 Content-Encoding 标头,而不是 Content-Transfer-Encoding 标头。映射是表驱动的。编码后缀区分大小写;类型后缀首先尝试区分大小写,然后不区分大小写。可选的 strict 参数是一个标志,指定已知 MIME 类型的列表是否仅限于在 IANA 注册的官方类型。当 strict 为 True(默认)时,仅支持 IANA 类型;当 strict 为 False 时,还会识别一些额外的非标准但常用的 MIME 类型。
import mimetypes
print(mimetypes.guess_type("sample.html"))
在 Python 3.x 和 webapp 中,文件的 url 不能有扩展名或假扩展名。你应该安装 python-magic,使用
pip3 install python-magic
对于 Mac OS X,您还应该使用安装 libmagic
brew install libmagic
代码片段
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)
我首先尝试 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
我很惊讶没有人提到它,但 Pygments 能够对 MIME 类型(尤其是文本文档)做出有根据的猜测。
Pygments 实际上是一个 Python 语法高亮库,但它有一种方法可以有根据地猜测您的文档是 500 种支持的文档类型中的哪一种。即c++ vs C# vs Python vs等
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 种文档格式中的哪一种,这非常有用。
mimetypes 模块仅根据文件扩展名识别文件类型。如果您将尝试恢复没有扩展名的文件的文件类型,则 mimetypes 将不起作用。
对于字节数组类型数据,您可以使用 magic.from_buffer(_byte_array,mime=True)
我尝试了很多示例,但使用 Django mutagen 效果很好。
检查文件是否为 mp3
的示例
from mutagen.mp3 import MP3, HeaderNotFoundError
try:
audio = MP3(file)
except HeaderNotFoundError:
raise ValidationError('This file should be mp3')
缺点是您检查文件类型的能力有限,但如果您不仅要检查文件类型,还要访问其他信息,这是一个很好的方法。
import magic
,但内容不兼容。有关更多信息,请参见stackoverflow.com/a/16203777/3189。