You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

修改要点:

  1. 添加content_encoding='gzip':告知GCS该Blob为gzip压缩格式,下载时自动执行解压;
  2. 设置content_type='application/json':明确文件类型,与gsutil cp -Z的默认行为保持一致;
  3. 优化字节流处理:直接基于orjson.dumps返回的字节进行压缩,减少字符串转换带来的开销和潜在编码问题。

修改完成后,二次下载时blob.download_as_bytes()会自动获取解压后的JSON字节,orjson.loads即可正常解析。

内容的提问来源于stack exchange,提问作者Eugene Shtoka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:35:01