使用C#调用Google.Apis.Drive.v3下载文件得到零字节空文件求助
解决Google Drive API v3下载文件出现零字节的问题
嘿,我看到你在使用C#结合Google.Apis.Drive.v3下载文件时遇到了零字节空文件的问题,这大概率是因为你用错了API方法——Export接口只适用于Google原生格式的文件(比如Google Docs、Sheets、Slides这类在线文档),用来将它们导出为PDF、docx等格式。如果是普通的非Google原生文件(比如本地上传的PDF、图片、压缩包等),使用Export就会返回空内容,这就是你得到零字节文件的原因。
下面是具体的修复方案:
1. 区分文件类型,选择正确的下载方式
首先要判断目标文件是否是Google原生格式,我们可以通过文件的mimeType来识别:
- Google原生格式的MIME类型都以
application/vnd.google-apps.开头(比如application/vnd.google-apps.document对应Google Docs) - 非原生格式直接使用
Files.Get方法下载
2. 修复你的下载代码
替换你原来的下载逻辑部分,以下是修改后的完整代码片段:
static string[] Scopes = { DriveService.Scope.Drive }; static string ApplicationName = "Test001"; private DriveService _service = null; public async Task DownloadFile(string url, string lstrDownloadFile) { // 授权API访问(改用await避免同步阻塞) UserCredential credential; using (var stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read)) { string credPath = "token.json"; // 把.Result改成await,符合异步方法的规范 credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( GoogleClientSecrets.Load(stream).Secrets, Scopes, "user", CancellationToken.None, new FileDataStore(credPath, true)); Debug.WriteLine("Credential file saved to: " + credPath); } // 创建Drive API服务 _service = new DriveService(new BaseClientService.Initializer() { HttpClientInitializer = credential, ApplicationName = ApplicationName, }); // 优化:直接从URL提取文件ID,不用遍历所有文件 string fileId = ExtractFileIdFromUrl(url); if (string.IsNullOrEmpty(fileId)) { Debug.WriteLine("无法从URL中提取文件ID"); return; } // 获取文件详情 var file = await _service.Files.Get(fileId).ExecuteAsync(); Debug.WriteLine($"{file.OriginalFilename}: {file.MimeType}"); MemoryStream lobjMS = new MemoryStream(); // 根据文件类型选择下载方式 if (file.MimeType.StartsWith("application/vnd.google-apps.")) { // Google原生文件,选择合适的导出格式(比如导出为PDF,你可以根据需求调整) string exportMimeType = GetExportMimeType(file.MimeType); if (string.IsNullOrEmpty(exportMimeType)) { Debug.WriteLine("该Google原生文件不支持导出为指定格式"); return; } var exportRequest = _service.Files.Export(fileId, exportMimeType); await exportRequest.DownloadAsync(lobjMS); } else { // 普通文件,直接下载 var getRequest = _service.Files.Get(fileId); await getRequest.DownloadAsync(lobjMS); } // 将内存流写入本地文件 lobjMS.Position = 0; using (var lobjFS = new FileStream(lstrDownloadFile, FileMode.Create, FileAccess.Write)) { await lobjMS.CopyToAsync(lobjFS); } } // 辅助方法:从Google Drive URL提取文件ID private string ExtractFileIdFromUrl(string url) { // 处理常见的Google Drive URL格式,比如 https://drive.google.com/file/d/{fileId}/view... var uri = new Uri(url); if (uri.Host == "drive.google.com") { if (uri.Segments.Length >= 3 && uri.Segments[1] == "file/" && uri.Segments[2] == "d/") { return uri.Segments[3].Split('/')[0]; } // 处理带?id=xxx的URL格式 var queryParams = System.Web.HttpUtility.ParseQueryString(uri.Query); return queryParams["id"]; } return null; } // 辅助方法:根据Google原生文件类型获取对应的导出MIME类型 private string GetExportMimeType(string googleMimeType) { return googleMimeType switch { "application/vnd.google-apps.document" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document", // docx "application/vnd.google-apps.spreadsheet" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // xlsx "application/vnd.google-apps.presentation" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", // pptx "application/vnd.google-apps.document" => "application/pdf", // 也可以导出为PDF // 更多格式映射可以参考Google Drive API文档 _ => null }; }
3. 额外的优化说明
- 避免同步阻塞:原来的代码中用
.Result等待异步授权,这可能导致死锁问题,改成await更符合异步编程规范。 - 直接提取文件ID:遍历所有文件来找目标文件效率极低,通过URL直接提取ID能大幅提升性能。
- 资源释放:使用
using语句包裹FileStream,确保文件流被正确释放。
这样修改后,无论是普通文件还是Google原生文件,都能正确下载到内容,不会出现零字节的问题了。
内容的提问来源于stack exchange,提问作者NickSO
相关产品推荐
相关产品推荐

