最稳妥方式是使用google.cloud.storage.v1客户端库异步上传:先配置服务账号凭证(本地设google_application_credentials环境变量,部署时确保默认服务账号有storage.objects.create权限),小文件直接用uploadobjectasync,大文件启用enableresumableupload分块上传。

如何用C#上传文件到Google Cloud Storage(GCS)
直接用 Google.Cloud.Storage.V1 客户端库最稳妥,官方维护、支持异步、能处理大文件分块上传。别自己拼HTTP请求或用过时的 Google.Apis.Storage.v1,容易卡在认证或超时上。
必须配置服务账号凭证并设置环境变量
不设好凭证,StorageClient.Create() 会静默失败或抛出 GoogleApiException: The caller does not have permission。不是代码写错了,是根本没登录。
- 从GCP控制台下载服务账号JSON密钥文件(如
my-project-123456-abcde789.json) - 本地开发时,在终端执行:
set GOOGLE_APPLICATION_CREDENTIALS="C:\path\to\my-project-123456-abcde789.json"
(Windows)或export GOOGLE_APPLICATION_CREDENTIALS="/path/to/my-project-123456-abcde789.json"
(Linux/macOS) - 部署到Compute Engine或Cloud Run时,可跳过此步——用默认服务账号,但需确保该账号有
roles/storage.objectAdmin权限
上传小文件:用 UploadObjectAsync 最简单
适合几MB以内的文件,内存占用低、代码直白。注意:它把整个文件读进内存再发,别用它传500MB视频。
var client = StorageClient.Create();
await client.UploadObjectAsync(
bucket: "my-bucket-name",
objectName: "uploads/photo.jpg",
contentType: "image/jpeg",
source: File.OpenRead(@"C:\local\photo.jpg"));-
objectName是GCS里显示的路径,支持子目录(如logs/2024/04/app.log),但没有“文件夹”概念 - 不传
contentType会导致GCS默认设为application/octet-stream,浏览器可能无法直接预览图片/PDF - 如果要覆盖已有文件,无需额外操作——GCS默认覆盖;如需禁止覆盖,得先调用
GetObjectMetadataAsync判断是否存在
上传大文件:必须用 UploadObjectOptions 启用分块上传
超过10MB建议显式启用分块(resumable upload),否则可能因网络抖动失败且无法续传。默认情况下 UploadObjectAsync 对大文件也会自动切片,但加选项更可控。
var options = new UploadObjectOptions
{
EnableResumableUpload = true,
ChunkSize = 5 * 1024 * 1024 // 5MB每块
};
await client.UploadObjectAsync("my-bucket", "big.zip", "application/zip",
File.OpenRead(@"C:\big.zip"), options);-
ChunkSize必须是256KB的整数倍,最小256KB,最大5GB;太小增加HTTP开销,太大内存压力高 - 上传中途断掉?只要没删掉临时上传ID,下次用同一
objectName调用仍会自动续传(前提是没关掉EnableResumableUpload) - 不要手动实现分块逻辑——客户端库已封装好,自己搞容易漏掉校验和或重试逻辑
最容易被忽略的是权限粒度:GCS的IAM策略按bucket甚至object前缀控制,不是项目级开关。传不上去时,先确认服务账号对目标bucket有 storage.objects.create 权限,而不是只给了 storage.buckets.list。










