GCS Python SDK实现与gsutil cp -Z等效上传功能报错求助
问题
我在实现从GCS下载gzip压缩文件、处理后重新上传的流程时遇到问题:
- 使用
blob.download_as_bytes()可以自动解压文件,正常完成反序列化; - 但自定义的
upload_object方法,在处理通过gsutil cp -Z上传的文件并重新上传后,二次下载时orjson.loads会报UTF-8格式错误。
需要修改upload_object,实现和gsutil cp -Z相同的效果。
相关代码:
def download_object(blob: storage.Blob): bytes_buffer = blob.download_as_bytes() dict_data = orjson.loads(bytes_buffer) return load_from_dict(dict_data) def upload_object(blob: storage.Blob, obj): dict_data = obj.save_as_dict() json_string = orjson.dumps(dict_data).decode("utf-8") compressed = gzip.compress(json_string.encode("utf-8")) blob.upload_from_string(compressed)
报错信息:
orjson.JSONDecodeError: str is not valid UTF-8: surrogates not allowed: line 1 column 1 (char 0)
解决方案
问题核心是元数据缺失:gsutil cp -Z上传时会自动给Blob添加Content-Encoding: gzip元数据,GCS返回这类Blob时会自动解压,所以download_as_bytes()拿到的是解压后的JSON字节。而你的自定义上传只传了压缩内容,未设置该元数据,导致GCS返回原始gzip压缩字节,orjson.loads直接解析压缩字节自然触发UTF-8错误。
修改upload_object,补充元数据设置,同时优化字节处理步骤:
def upload_object(blob: storage.Blob, obj): dict_data = obj.save_as_dict() # 直接使用orjson输出的字节,避免不必要的字符串解码再编码 json_bytes = orjson.dumps(dict_data) compressed = gzip.compress(json_bytes) # 上传时指定编码类型和内容类型,对齐gsutil cp -Z的行为 blob.upload_from_string( compressed, content_type='application/json', content_encoding='gzip' )
修改要点:
- 添加
content_encoding='gzip':告知GCS该Blob为gzip压缩格式,下载时自动执行解压; - 设置
content_type='application/json':明确文件类型,与gsutil cp -Z的默认行为保持一致; - 优化字节流处理:直接基于
orjson.dumps返回的字节进行压缩,减少字符串转换带来的开销和潜在编码问题。
修改完成后,二次下载时blob.download_as_bytes()会自动获取解压后的JSON字节,orjson.loads即可正常解析。
内容的提问来源于stack exchange,提问作者Eugene Shtoka
相关产品推荐
相关产品推荐

