InMemoryUploadedFile转Google MediaUpload触发UnicodeDecodeError
问题根因
- Google App Engine标准环境实例的文件系统为只读模式,Django接收体积小于默认阈值的上传文件时,会自动生成内存存储的
InMemoryUploadedFile实例,不会写入本地磁盘,该行为符合环境特性。 - 你使用的
MediaFileUpload类仅支持传入本地文件路径入参,会自行从磁盘读取文件内容,不支持直接传入内存文件实例或者bytes对象。你把读取到的字节内容当文件路径传入后,类内部会尝试将字节作为路径字符串解析,最终触发类型错误、UnicodeDecodeError。
修复方案
替换上传类为专门适配内存流的MediaIoBaseUpload,全程不需要写入本地磁盘,完全适配GAE只读环境:
- 补充导入所需依赖
import io from googleapiclient.http import MediaIoBaseUpload
- 修正上传逻辑,替换原有
MediaFileUpload相关代码即可,完整参考实现:
def expupdate(request): try: creds, _ = google.auth.default() service = build('drive', 'v3', credentials=creds) myfile = request.FILES['archivo'] Mtype = myfile.content_type # 小文件方案:读字节包装为内存流 file_stream = io.BytesIO(myfile.read()) media = MediaIoBaseUpload( file_stream, mimetype=Mtype, resumable=False ) # 大文件优化方案:不需要全量读入内存,直接传InMemoryUploadedFile实例即可 # 该类本身实现了标准类文件read接口,内存占用更低 # media = MediaIoBaseUpload(myfile, mimetype=Mtype, resumable=True) file_metadata = {'name': 'test.jpeg'} file = service.files().create( body=file_metadata, media_body=media, fields='id' ).execute() fileid = file.get("id") print(fileid) file_stream.close() except Exception as e: print('An error occurred:') print(e)
避坑提示
- 不要对上传文件的二进制内容做任何字符串解码操作,图片、办公文档等二进制文件做字符串解码必然触发
UnicodeDecodeError。 - 上传体积超过10M的文件建议将
resumable参数设为True,开启分片续传,避免大文件上传超时。 - 不需要额外把
InMemoryUploadedFile转成bytes再包装,直接传入MediaIoBaseUpload就能正常工作,可减少一次内存拷贝。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

