2012-11-14 4 views
1

사용자가 파일을 업로드 할 수있는 플라스크 기반 웹 앱이 있습니다. 파일은 mysql 데이터베이스에 저장된다.pymysql로 ​​큰 blob을 삽입하려고 할 때 깨진 파이프

파일이 경우 16MB 이상 될 때까지 잘 작동이 삽입은 다음과 실패 다음 파일 크기가 max_allowed_packet 설정 MySQL의에 맞게 나타 났을 때 나는 흥분

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')) 

, 그래서 나는 my.cnf에 변경 다시 시작했지만 도움이되지 않았습니다. (show variables like 'max_allowed_packet'은 새로운 150M 값을 보여줍니다.)

파일이 서버에 확실히 업로드되고, 필자는 쿼리를 실행하기 전에 파일을 디스크에 쓰는 코드를 삽입 메소드에 넣었습니다.

블롭에 삽입되고있는 필드가 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" 

, 나는 일주일에 몇 가지 물건을 찾을 않았거나 전에는 파일을 섹션에 삽입해야한다고 제안했지만 지금은 찾을 수 없습니다 (실제 작업에 정신이 없습니다!). 그리고 그것을 덩어리로 삽입하는 방법을 모르겠습니다.

정말 고맙겠습니다.

답변

0

먼저 파일을 안전한 크기의 블록으로 채우기를 원할 것입니다. 귀하의 경우에는 10MB로 만들 수 있습니다. 이 대답에 chunks function을 사용하면됩니다. 그런 다음 데이터의 첫 번째 청크를 삽입하고 그 청크에 추가 청크를 연결하는 일련의 업데이트를 수행합니다. 해당 부분을 수행하려면 append/concatenate BLOB data to a BLOB column using update?에 대한 질문을 확인하십시오.

+0

감사합니다. 이것은 한 걸음 더 나아갑니다. 파일을 청크로 나누고 각 청크를 추가하는 메소드를 프로토 타입했습니다. 파일을 다운로드 할 수 없으면'select' 쿼리는 파일이 ~ 16MB보다 큰 빈 결과를 반환합니다. 나는 역으로 같은 것을 할 필요가 있다고 생각하지만, 어떻게? 이상적으로 나는 오히려 1 거래에 더 큰 물건을 삽입 할 수있을 것입니다! – MalphasWats

+0

선택에 문제가 없어야합니다. 대형 BLOB가 올바르게 작성되었는지 여부를 mysql 클라이언트에서 직접 확인하는 것이 좋습니다. –

+0

큰 BLOB가 phpmyadmin을 사용하여 올바르게 작성되었으므로 BLOB 필드의 내용을 저장하고 적절한 확장자로 이름을 바꾸면 파일이 열립니다. pymysql을 통해 파일을 쿼리하려고하면 빈 결과가 나타납니다. 'select'는'insert'와 같은 제약을받습니다. – MalphasWats

0

이것은 또 다른 접근법입니다. LOAD_FILE 기능을 사용하여 blob 열에 파일을로드하십시오.

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

16MB의 제한 사항이 적용되지 않아야합니다. 바이너리 인코딩 문제가있는 경우 이미지를 파이썬으로 16 진수 형식으로 저장 한 다음 UNHEX을 사용하여 안전하게 원시 바이너리 형식으로 다시 디코딩 할 수 있습니다. 웹 서버는이 당신이로 파일을 전송 SCP 또는 FTP 같은 것을 사용 할 수도, 그렇지 않으면 사소한 동일한 서버에있는 경우

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

두 옵션은하지만 MySQL 서버의 파일 시스템에 파일을 저장하기 위해 당신이 필요 SQL 문을 발행하기 전에 MySQL 서버.

관련 문제