求助:使用Dropbox API无法获取完整目录文件列表的问题
问题描述
我开发了两个应用:一个负责将数据压缩包上传至对应公司的指定文件夹,运行正常;另一个用于将这些压缩包拉取到客户站点做本地备份,在文件数量达到约700个后出现问题。我通过调用Dropbox API请求指定目录下的压缩文件列表,解析文件名中的创建时间以获取最新文件,但API未返回完整列表,导致无法获取正确的文件。
原代码如下:
private static string GetFileFromDropbox() { try { var client = CreateDropBoxInstance(); var pathtofiles = $"/{Settings.Default.CompanyCode}"; //var list = await client.Files.ListFolderGetLatestCursorAsync(pathtofiles); // changed 11/9/22 by Eric since it was not returning all files //var list = client.Files.ListFolderAsync(pathtofiles); var list = client.Files.ListFolderAsync(pathtofiles, true, true, false); var newlist = new List<string>(); foreach (var l in list.Result.Entries) { if (!l.IsFile) continue; newlist.Add(l.PathLower.Replace($"/{Settings.Default.CompanyCode.ToLower()}/", string.Empty)); } var dict = new Dictionary<DateTime, string>(); foreach (var fn in newlist) { // filename: AAB.20211126234249.zip var parse = fn.Split('.'); if (parse.Length != 3) continue; var date = parse[1]; // cc yy mm dd hh mm ss // 20 21 11 26 23 42 49 // 01 23 45 67 89 1011 1213 if (date.Length != 14) continue; var cc = int.Parse(date.Substring(0, 2)); var yy = int.Parse(date.Substring(2, 2)); var mm = int.Parse(date.Substring(4, 2)); var dd = int.Parse(date.Substring(6, 2)); var hh = int.Parse(date.Substring(8, 2)); var mi = int.Parse(date.Substring(10, 2)); var ss = int.Parse(date.Substring(12, 2)); var filedate = new DateTime(cc + yy, mm, dd, hh, mi, ss); dict.Add(filedate, fn); } var qry = (from x in dict orderby x.Key descending select x.Value).FirstOrDefault(); return qry; } catch (Exception e) { Console.WriteLine(e); throw; } }
解决方案
Dropbox API的ListFolderAsync会分页返回结果,当存在未返回的剩余文件时,返回结果的HasMore属性为true,同时会提供Cursor参数,需要通过ListFolderContinueAsync循环获取所有分页数据,直到HasMore为false。
另外原代码还存在两个关键问题:
- 同步调用异步方法(
list.Result)易引发死锁,建议改为异步方法。 - 日期解析逻辑错误:
cc + yy会将年份计算为41(比如20+21),正确应为cc*100 + yy得到完整年份(如2021)。 Dictionary<DateTime, string>存在重复键风险,若两个文件时间戳完全相同,dict.Add会抛出异常,建议改用列表存储后排序。
修改后的代码
private static async Task<string> GetFileFromDropboxAsync() { try { var client = CreateDropBoxInstance(); var pathtofiles = $"/{Settings.Default.CompanyCode}"; var newlist = new List<string>(); // 首次调用获取初始文件列表 var listResult = await client.Files.ListFolderAsync(pathtofiles, true, true, false); AddFilesToList(listResult.Entries, newlist); // 循环获取剩余分页数据 while (listResult.HasMore) { listResult = await client.Files.ListFolderContinueAsync(listResult.Cursor); AddFilesToList(listResult.Entries, newlist); } // 存储文件时间与文件名,避免重复键问题 var fileInfos = new List<(DateTime FileDate, string FileName)>(); foreach (var fn in newlist) { // filename: AAB.20211126234249.zip var parse = fn.Split('.'); if (parse.Length != 3) continue; var dateStr = parse[1]; if (dateStr.Length != 14) continue; // 正确解析完整年份 var year = int.Parse(dateStr.Substring(0, 4)); var month = int.Parse(dateStr.Substring(4, 2)); var day = int.Parse(dateStr.Substring(6, 2)); var hour = int.Parse(dateStr.Substring(8, 2)); var minute = int.Parse(dateStr.Substring(10, 2)); var second = int.Parse(dateStr.Substring(12, 2)); var filedate = new DateTime(year, month, day, hour, minute, second); fileInfos.Add((filedate, fn)); } // 按时间倒序获取最新文件 return fileInfos.OrderByDescending(x => x.FileDate).Select(x => x.FileName).FirstOrDefault(); } catch (Exception e) { Console.WriteLine(e); throw; } } // 提取重复逻辑,提升代码复用性 private static void AddFilesToList(IEnumerable<Metadata> entries, List<string> fileList) { foreach (var entry in entries) { if (entry.IsFile) { var fileName = entry.PathLower.Replace($"/{Settings.Default.CompanyCode.ToLower()}/", string.Empty); fileList.Add(fileName); } } }
关键修改点说明
- 将方法改为异步
Task<string>类型,使用await调用API,避免同步阻塞与死锁。 - 新增分页循环:通过
HasMore判断是否有剩余数据,结合Cursor调用ListFolderContinueAsync获取全部文件。 - 修正日期解析逻辑:直接截取前4位作为完整年份,避免原代码的计算错误。
- 改用
List<(DateTime, string)>存储文件信息,规避Dictionary的重复键异常。 - 提取
AddFilesToList方法,减少代码冗余,提升可读性。
内容的提问来源于stack exchange,提问作者ErocM
相关产品推荐
相关产品推荐

