1

我有一个基于烧瓶的网络应用程序,允许用户上传文件。文件存储在 mysql 数据库中。

这工作正常,直到文件大于大约 16Mb,插入失败并显示以下内容:

File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1518, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1506, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1504, in wsgi_app
    response = self.full_dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1264, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1262, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1248, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/<redacted>/access_control.py", line 15, in decorated_function
    return f(*args, **kwargs)
  File "/<redacted>/views/files.py", line 48, in upload
    VALUES (%s, %s, %s, %s, %s)""", file_details)
  File "/<redacted>/database.py", line 66, in query
    cursor.execute(sql, values)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 262, in execute
    result = super(DictCursor, self).execute(query, args)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/cursors.py", line 117, in execute
    self.errorhandler(self, exc, value)
  File "/usr/local/lib/python2.7/dist-packages/pymysql/connections.py", line 187, in defaulterrorhandler
    raise Error(errorclass, errorvalue)
Error: (<class 'socket.error'>, error(32, 'Broken pipe'))

当文件大小似乎与 mySQL 设置匹配时,我很兴奋max_allowed_packet,所以我将其更改my.cnf并重新启动,但它没有帮助。(show variables like 'max_allowed_packet'显示新值150M)

该文件肯定会上传到服务器,我在我的插入方法中放入了一些代码,以便在运行查询之前将文件写入磁盘并且文件没问题。

插入 blob 的字段是一个 longblob,负责插入的代码是:

@mod.route('/file/upload', methods=['POST'])
@login_required
def upload():
    filename = request.files['file'].filename
    mime_type = request.files['file'].mimetype
    #filesize = request.files['file'].content_length
    file = request.files['file'].stream.read()

    if mime_type[:5] == 'image':
        file = resize_image_to_width(file, 1024)

    filesize = len(file)
    if filesize == 0:
        return ""

    if not request.form['file_id']:
        file_details = (filename, file, mime_type, filesize, session['user']['user_id'])
        file_id = database.query("""INSERT INTO files (filename, file, mime_type, filesize, owner)
                                      VALUES (%s, %s, %s, %s, %s)""", file_details)
    else:
        file_details = (filename, file, mime_type, filesize, request.form['file_id'])

        file_id = database.query("""UPDATE files 
                                    SET 
                                        filename=%s, 
                                        file=%s, 
                                        mime_type=%s, 
                                        filesize=%s 
                                    WHERE file_id=%s""", file_details)
    return "upload complete"

我现在有点不知所措,大约一周前我确实找到了一些建议文件需要分段插入的东西,但我现在找不到(我被我的实际工作分心了! ) 而且我不知道如何将它分块插入。

我真的很感激这方面的帮助!

4

2 回答 2

0

首先,您要将文件分块成可以安全插入的块,在您的情况下,您可以制作 10MB。您可以使用该答案中的chunks 函数来执行此操作。然后你插入你的第一个数据块并进行一系列更新,将额外的数据块连接到那个 blob 上。要执行该部分,请查看有关使用更新将 BLOB 数据附加/连接到 BLOB 列的问题?.

于 2012-11-14T10:37:51.843 回答
0

这是另一种方法。使用LOAD_FILE函数将文件加载到 blob 列中。

UPDATE t SET blob_col=LOAD_FILE('/tmp/image.png') WHERE id=1;

这不应该面临您拥有的 16MB 限制。如果您遇到任何二进制编码问题,您可以使用 python 以十六进制格式保存图像,然后使用UNHEX将其安全地解码回原始二进制形式。

UPDATE t SET blob_col=UNHEX(LOAD_FILE('/tmp/image.png.hex')) WHERE id=1;

如果您的网络服务器位于同一台服务器上,这两个选项都需要您将文件保存在 MySQL 服务器文件系统上,否则您可能必须使用 scp 或 ftp 之类的东西将文件传输到 MySQL 服务器,然后再发出 SQL 语句.

于 2012-11-14T14:32:07.073 回答