Как записывать большие файлы в Blobstore с помощью экспериментального API?

У меня дилемма. Я загружаю файлы как в магазин scribd, так и в магазин BLOB-объектов, используя tipfy в качестве фреймворка. У меня есть веб-форма с действием, не созданным blobstore.create_upload_url (я просто использую url_for('myhandler')). Я сделал это, потому что, если я использую обработчик blobstore, ответ POST анализируется, и я не могу использовать обычный API-интерфейс python-scribd для загрузки файла в хранилище scribd. Теперь у меня есть рабочая заставка scribd:

class UploadScribdHandler(RequestHandler, BlobstoreUploadMixin):
    def post(self):
        uploaded_file = self.request.files.get('upload_file')
        fname = uploaded_file.filename.strip()
        try:
            self.post_to_scribd(uploaded_file, fname)
        except Exception, e:
            # ... get the exception message and do something with it
            msg = e.message
            # ...
        # reset the stream to zero (beginning) so the file can be read again
        uploaded_file.seek(0)
        #removed try-except to see debug info in browser window
        # Create the file

        file_name = files.blobstore.create(_blobinfo_uploaded_filename=fname)
        # Open the file and write to it
        with files.open(file_name, 'a') as f:
            f.write(uploaded_file.read())
        # Finalize the file. Do this before attempting to read it.      
        files.finalize(file_name)
        # Get the file's blob key
        blob_key = files.blobstore.get_blob_key(file_name)

        return Response('done')

    def post_to_scribd(self, uploaded_file, fname):
        errmsg =''
        uploaded_file = self.request.files.get('upload_file')
        fname = uploaded_file.filename.strip()
        fext = fname[fname.rfind('.')+1:].lower()
        if (fext not in ALLOWED_EXTENSION):
            raise Exception('This file type does not allowed to be uploaded\n')
        if SCRIBD_ENABLED:
            doc_title = self.request.form.get('title')
            doc_description = self.request.form.get('description')
            doc_tags = self.request.form.get('tags')
            try:
                document = scribd.api_user.upload(uploaded_file, fname, access='private')
                #while document.get_conversion_status() != 'DONE':
                #   time.sleep(2)
                if not doc_title:
                    document.title = fname[:fname.rfind('.')]
                else:
                    document.title = doc_title
                if not doc_description:
                    document.description = 'This document was uploaded at ' + str(datetime.datetime.now()) +'\n'
                else:
                    document.description = doc_description
                document.tags = doc_tags
                document.save()
            except scribd.ResponseError, err:
                raise Exception('Scribd failed: error code:%d, error message: %s\n' % (err.errno, err.strerror))
            except scribd.NotReadyError, err:
                raise Exception('Scribd failed: error code:%d, error message: %s\n' % (err.errno, err.strerror))
            except:
                raise Exception('something wrong exception')

Как вы можете видеть, он также сохраняет файл в blobstore. Но если я загружаю большой файл (например, 5 МБ), я получаю

RequestTooLargeError: The request to API call file.Append() was too large.
Request: docs.upload(access='private', doc_type='pdf', file=('PK\x03\x04\n\x00\x00\x00\x00\x00"\x01\x10=\x00\x00(...)', 'test.pdf'))

Как я могу это исправить? Спасибо!


person minus    schedule 12.04.2011    source источник
comment
Ваш вопрос и ответы на него мне очень помогли, ура!   -  person selurvedu    schedule 14.09.2015


Ответы (2)


Вам нужно сделать несколько небольших вызовов файлового API, например, так:

with files.open(file_name, 'a') as f:
    data = uploaded_file.read(65536)
    while data:
      f.write(data)
      data = uploaded_file.read(65536)

Обратите внимание, что предельный размер полезной нагрузки для обычных запросов к приложениям App Engine составляет 10 МБ. если вы хотите загружать файлы большего размера, вам потребуется использовать обычный механизм загрузки в хранилище BLOB-объектов.

person Nick Johnson    schedule 13.04.2011
comment
Используя ваш пример кода, можете ли вы подумать, почему он выдает AttributeError - объект «InMemoryUploadedFile» не имеет атрибута «eof»? (На второй строке вашего примера) - person ductionist; 11.05.2011
comment
@bfox Предположительно, потому что у него нет этого атрибута. Я обновлю свой ответ альтернативой. - person Nick Johnson; 11.05.2011
comment
@minus Вы придумали обходной путь? У меня та же проблема, что и у вас, при попытке загрузить файл размером 3-4 МБ в blobstore. - person Matt; 28.06.2011
comment
@Matt Что не так с решением, которое я опубликовал? И почему бы не загрузить его напрямую, используя загрузку в blobstore? - person Nick Johnson; 28.06.2011

наконец я нашел решение.

В ответе Ника Джонсона произошла ошибка атрибута, поскольку uploaded_file обрабатывается как строка. строка не имеет метода read().

Поскольку у строки нет метода read(), я соединил строку файла и написал ее так же, как он написал.

class UploadRankingHandler(webapp.RequestHandler):
  def post(self):
    fish_image_file = self.request.get('file')

    file_name = files.blobstore.create(mime_type='image/png', _blobinfo_uploaded_filename="testfilename.png")

    file_str_list = splitCount(fish_image_file,65520)

    with files.open(file_name, 'a') as f:
      for line in file_str_list:
        f.write(line)

вы можете проверить о splitCount(). здесь

http://www.bdhwan.com/entry/gaewritebigfile

person Robert Bae Dong Hwan    schedule 18.08.2011