如何使用实验性 API 将大文件写入 Blobstore?
Posted
技术标签:
【中文标题】如何使用实验性 API 将大文件写入 Blobstore?【英文标题】:How to write Big files into Blobstore using experimental API? 【发布时间】:2011-08-04 01:52:47 【问题描述】:我有两难选择。我正在使用tipfy 作为框架在scribd 存储和blobstore 中上传文件。 我的网络表单不是由 blobstore.create_upload_url 创建的(我只是使用 url_for('myhandler'))。我这样做是因为如果我使用 blobstore 处理程序解析 POST 响应并且我不能使用普通的 python-scribd api 将文件上传到 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 中。但如果我要上传大文件(即 5Mb),我会收到
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'))
我该如何解决? 谢谢!
【问题讨论】:
您的问题及其答案对我帮助很大,干杯! 【参考方案1】:您需要对文件 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 应用的常规请求的有效负载大小限制为 10MB;如果要上传较大的文件,则需要使用常规的 blobstore 上传机制。
【讨论】:
使用您的示例代码,您能想到为什么它会给出 AttributeError - 'InMemoryUploadedFile' 对象没有属性 'eof'? (在你的例子的第二行) @bfox 大概是因为它没有那个属性。我会用另一种方法更新我的答案。 @minus 你有没有想出一个解决方法?在尝试将 3-4 MB 文件上传到 blobstore 时,我遇到了与您相同的问题。 @Matt 我发布的解决方案有什么问题?为什么不直接使用 blobstore 上传呢?【参考方案2】:终于找到解决办法了。
Nick Johneson 的回答发生属性错误,因为 upload_file 被视为字符串。 string 没有 read() 方法。
因为string没有read()方法,我把文件string拼接成他写的那样写。
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
【讨论】:
以上是关于如何使用实验性 API 将大文件写入 Blobstore?的主要内容,如果未能解决你的问题,请参考以下文章