首页 > 解决方案 > Python如何在编写和重命名文件后为谷歌云存储文件生成签名的url?

问题描述

我通过将文件从 BigQuery 导出到 Google Cloud 存储来构建文件以供下载。其中一些文件相对较大,因此它们必须在被 BigQuery 导出分片后组合在一起。

用户输入将在前端生成的文件的文件名。在后端,我正在生成一个随机的临时名称,以便我可以将文件组合在一起。

# Job Configuration for the job to move the file to bigQuery
job_config = bigquery.QueryJobConfig()
job_config.destination = table_ref
query_job = client.query(sql, job_config=job_config)
query_job.result()

# Generate a temporary name for the file
fname = "".join(random.choices(string.ascii_letters, k=10))
# Generate Destination URI
destinationURI = info["bucket_uri"].format(filename=f"{fname}*.csv")
extract_job = client.extract_table(table_ref, destination_uris=destinationURI, location="US")
extract_job.result()
# Delete the temporary table, if it doesn't exist ignore it
client.delete_table(f"{info['did']}.{info['tmpid']}", not_found_ok=True)

数据导出完成后,我通过将 blob 组合在一起来拆分文件。

client = storage.Client(project=info["pid"])
bucket = client.bucket(info['bucket_name'])
all_blobs = list(bucket.list_blobs(prefix=fname))
blob_initial = all_blobs.pop(0)

prev_ind = 0
for i in range(31, len(all_blobs), 31):
    # Compose files in chunks of 32 blobs (GCS Limit)
    blob_initial.compose([blob_initial, *all_blobs[prev_ind:i]])
    # PREVENT GCS RATE-LIMIT FOR FILES EXCEEDING ~100GB
    time.sleep(1.0)
    prev_ind = i
else:
    # Compose all remaining files when less than 32 files are left
    blob_initial.compose([blob_initial, *all_blobs[prev_ind:]])

for b in all_blobs:
    # Delete the sharded files
    b.delete()

将所有文件组合成一个文件后,我将 blob 重命名为用户提供的文件名。然后我生成一个签名的 URL,该 URL 被发布到前端的 firebase 以提供文件供下载。

# Rename the file to the user provided filename
bucket.rename_blob(blob_initial, data["filename"])
# Generate signed url to post to firebase
download_url = blob_initial.generate_signed_url(datetime.now() + timedelta(days=10000))

我遇到的问题是因为使用了文件分片时使用的随机文件名。我选择使用随机文件名而不是用户提供的文件名的原因是因为可能存在多个用户使用相同(默认值)文件名提交请求的情况,因此这些边缘情况会导致文件分片问题.

当我尝试下载文件时,我得到以下返回:

<Error>
    <Code>NoSuchKey</Code>
    <Message>The specified key does not exist.</Message>
    <Details>No such object: project-id.appspot.com/YMHprgIqMe000000000000.csv</Details> 
</Error>

尽管我重命名了文件,但下载 URL 似乎仍在使用旧文件名。当我生成签名 URL 时,有没有办法通知 GCS 文件名已更改?

标签: pythongoogle-bigquerygoogle-cloud-storage

解决方案


似乎只需要重新加载 blob!

bucket.rename_blob(blob_initial, data["filename"])

blob = bucket.get(data["filename"])

# Generate signed url to post to firebase
download_url = blob.generate_signed_url(datetime.now() + timedelta(days=10000))

推荐阅读