使用Flask/Python,从上传的文件中获取MIME类型

21

我正在使用 Flask 0.6 微框架和 Python 2.6

我需要从上传的文件中获取 mimetype,以便将其存储。

这是相关的 Python/Flask 代码:

@app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files['file']
        mimetype = #FIXME
        if file:
            file.save(os.path.join(UPLOAD_FOLDER, 'File-Name')
            return redirect(url_for('uploaded_file'))
        else:
            return redirect(url_for('upload'))


以下为网页的代码:

<form action="upload_file" method=post enctype=multipart/form-data> 
Select file to upload: <input type=file name=file> 
<input type=submit value=Upload> 
</form> 
代码可以正常工作,但我需要在上传时获取MIME类型。我已经查看了Flask文档:http://flask.pocoo.org/docs/api/#incoming-request-data,所以我知道它确实获取了MIME类型,但我无法弄清如何检索它 - 作为文本字符串,例如'txt/plain'。
有什么想法吗?
谢谢。
2个回答

44
docs 中可以看到,file.content_type 包含完整的类型和编码,而 mimetype 只包含了 MIME 类型。
@app.route('/upload_file', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        file = request.files.get('file')
        if file:
            mimetype = file.content_type
            filename = werkzeug.secure_filename(file.filename)
            file.save(os.path.join(UPLOAD_FOLDER, filename)
            return redirect(url_for('uploaded_file'))
        else:
            return redirect(url_for('upload'))

非常感谢!下次我会记得关注Werkzeug文档的 :) - Jon Cox
2
@Jonathan:不用谢!这是从您提供的文档页面链接过来的。 - MattH
5
这种解决方案实际上存在问题,因为Werkzeug返回的mimetype是基于文件扩展名推断而来的。例如,将任何PDF文件重命名为something.png并上传,Werkzeug会告诉你它的mime类型是image/png,而正确的答案应该是application/pdf(使用python-magic库可以正确地告诉你)。 - Louis Chatriot
更新链接:https://werkzeug.palletsprojects.com/en/2.3.x/datastructures/#werkzeug.datastructures.FileStorage.content_type - dashingdove

10
你可以理论上使用request.files['YOUR_FILE_KEY'].content_type,但是实现(包括在werkzeug.datastructures中找到的)要么信任客户端提供的内容,要么使用mimetypes.guess_type,只检查文件扩展名(请参见Python文档此处)。
class FileMultiDict(MultiDict):

    """A special :class:`MultiDict` that has convenience methods to add
    files to it.  This is used for :class:`EnvironBuilder` and generally
    useful for unittesting.
    .. versionadded:: 0.5
    """

    def add_file(self, name, file, filename=None, content_type=None):
        """Adds a new file to the dict.  `file` can be a file name or
        a :class:`file`-like or a :class:`FileStorage` object.
        :param name: the name of the field.
        :param file: a filename or :class:`file`-like object
        :param filename: an optional filename
        :param content_type: an optional content type
        """
        if isinstance(file, FileStorage):
            value = file
        else:
            if isinstance(file, string_types):
                if filename is None:
                    filename = file
                file = open(file, 'rb')
            if filename and content_type is None:
                content_type = mimetypes.guess_type(filename)[0] or \
                    'application/octet-stream'
            value = FileStorage(file, filename, name, content_type)

        self.add(name, value)

根据您的使用情况,您可能需要使用python-magic,它将使用实际文件获取MIME类型。示例代码如下:

import magic


def get_mimetype(data: bytes) -> str:
    """Get the mimetype from file data."""
    f = magic.Magic(mime=True)
    return f.from_buffer(data)


get_mimetype(request.files['YOUR_FILE_KEY'].stream.read(MAX_LENGTH))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接