异步从API下载JSON保存到文件时出现进程占用文件错误如何解决
核心问题定位
你遇到的错误不是多线程共享流导致的,根源是C# 循环变量闭包捕获的经典问题:
你在循环外部定义了计数变量i,传入Task.Run的lambda表达式捕获的是i的引用,而非每次循环时的瞬时值。当任务实际被调度执行时,循环已经完成了多轮自增,多个任务会拿到相同的i值,进而尝试写入同一路径的JSON文件。而你打开文件时设置了FileShare.None参数,不允许其他线程/进程同时访问该文件,因此直接抛出文件被占用的异常。
修复方案
在循环内部定义临时变量存储当前循环的计数,确保每个lambda捕获的是独立的计数变量:
public override async Task ExecuteCommandAsync(IEnumerable<string> urls) { string directory = "some directory"; int i = 0; foreach (var url in urls) { // 循环内部定义临时变量,每次循环生成独立的副本供lambda捕获 int currentIndex = i; tasks.Add(Task.Run(async () => { try { await DownloadJsonFromUrl(url, directory, currentIndex); } catch (Exception ex) { Console.WriteLine(ex.Message); } })); i++; Console.WriteLine($"task nr {i} started."); } await Task.WhenAll(tasks); }
其他可能的触发因素
- 路径拼接逻辑存在缺陷,比如
directory变量末尾没有添加路径分隔符(Windows下为\,Linux下为/),如果目录末尾的字符和数字拼接后和其他文件名重合,会意外触发重名冲突 - 外部进程锁定了目标文件,比如杀毒软件、文件同步工具正在扫描对应目录,可将
FileShare.None修改为FileShare.Read降低冲突概率 - 之前运行的程序异常退出后残留了未释放的文件句柄,可重启相关进程或开发环境清理残留句柄
- 输入的urls列表存在重复值,多个任务下载同一个url写入相同路径(如果你的逻辑允许重复url,建议给文件名增加随机后缀区分)
内容的提问来源于stack exchange,提问作者Dzemojad
相关产品推荐
相关产品推荐

