删除.json文件时触发System.IO.IOException问题求助
批量删除文件夹时随机出现JSON文件被占用无法删除的问题
我正在开发一套批量删除文件夹的系统,每个目标文件夹里都包含一个.json文件及其他文件/子目录。但每次执行删除操作时,总会有随机的.json文件因被其他进程占用而无法删除,触发System.IO.IOException。
我已尝试以下排查方案,但均无效:
- 将目录的
FileAttributes设置为Normal(曾解决其他非.json目录的同类问题) - 将访问目录的线程设为后台线程,确保应用停止后无残留线程
- 删除前关闭文件资源管理器
- 设置保存文件的流为
ReadWrite权限 - 释放写入.json文件的
StreamWriter而非关闭它
目前仅删除.json文件时会出现该异常,求问还有哪些遗漏的排查点?
相关代码
删除文件的函数
public static void DeleteBrains() { Console.WriteLine("Resetting brains..."); Dictionary<int, Thread> threads = new Dictionary<int, Thread>(); for (int i = 0; i < 100; i++) { DeleteDirProtector(i); } StartThreads(threads, false); void DeleteDirProtector(int i) { Thread thread = new Thread(() => DeleteDir(i)); threads.Add(i, thread); } void DeleteDir(int i) { string CurrentDir = $@"{DebugFolderPath}\Brain {i}"; if (Directory.Exists(CurrentDir)) { Console.WriteLine($"Deleting Brain {i}..."); File.SetAttributes(CurrentDir, FileAttributes.Normal); string[] directories = Directory.GetDirectories(CurrentDir); string[] files = Directory.GetFiles(CurrentDir); for (int j = 0; j < directories.Length; j++) { File.SetAttributes(directories[j], FileAttributes.Normal); } for (int j = 0; j < files.Length; j++) { File.SetAttributes(files[j], FileAttributes.Normal); } Directory.Delete(CurrentDir, true); } } }
保存JSON文件的函数
public void SaveBrain(bool isUpdate) { BrainSaveString = JsonConvert.SerializeObject(this, Formatting.Indented); string path = ""; if (isUpdate) { path = BrainSavePath2; } else if (!isUpdate) { path = BrainSavePath; } FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite); using (StreamWriter sw = new StreamWriter(stream)) { sw.Write(BrainSaveString); sw.Dispose(); } }
StartThreads方法
public static void StartThreads(Dictionary<int, Thread> threads, bool isBackground) { int threadCount = threads.Count; for (int i = 0; i < threadCount; i++) { try { if (threads[i].ThreadState == ThreadState.Unstarted) { while (!StartThread(threads[i], false, isBackground)){} } } catch (KeyNotFoundException) { } } while (threads.Count > 0) { for(int i = 0; i < threadCount; i++) { try { if (threads[i].ThreadState == ThreadState.Stopped) { threads.Remove(i); } } catch (KeyNotFoundException) { } } } }
StartThread方法
public static bool StartThread(Thread thread, bool ShouldRunAnyway, bool isBackground) { bool shouldStartThread = false; if (NumberOfThreads_ < NumberOfProcessors * 3) { shouldStartThread = true; } else { if (ShouldRunAnyway) { shouldStartThread = true; } } if (shouldStartThread) { thread.IsBackground = isBackground; thread.Start(); lock (AllThreadsBeingUsed) { AllThreadsBeingUsed.Add(thread); } } return shouldStartThread; }
遗漏的排查点及修复建议
修复SaveBrain方法的资源释放逻辑
你在SaveBrain中手动调用sw.Dispose(),但using块本身会自动释放StreamWriter及其持有的FileStream,手动调用可能导致资源释放不彻底。同时FileStream未被包裹在using中,存在流未完全关闭的风险。修改后的代码如下:public void SaveBrain(bool isUpdate) { BrainSaveString = JsonConvert.SerializeObject(this, Formatting.Indented); string path = isUpdate ? BrainSavePath2 : BrainSavePath; using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite)) using (StreamWriter sw = new StreamWriter(stream)) { sw.Write(BrainSaveString); } }排查内部线程的并发冲突
- 确认执行
DeleteBrains时,所有SaveBrain调用已完全结束,可通过全局锁或信号量确保保存操作全部完成后再启动删除线程。 - 用Windows的
Process Explorer工具搜索目标JSON文件路径,查看是否有本进程内的其他线程持有文件句柄。
- 确认执行
强制回收未释放的资源
CLR的垃圾回收可能延迟释放未被引用的文件句柄,可在删除前强制触发一次垃圾回收(仅排查阶段试用):GC.Collect(); GC.WaitForPendingFinalizers();将这段代码放在
Directory.Delete之前测试。检查第三方工具的文件锁定
杀毒软件、备份工具、Windows搜索索引服务等都可能临时锁定JSON文件,可临时关闭这些服务测试,或在删除前暂停索引服务。添加删除重试机制
随机出现的文件占用大概率是临时锁定,给删除操作加重试逻辑:void DeleteDir(int i) { string CurrentDir = $@"{DebugFolderPath}\Brain {i}"; if (!Directory.Exists(CurrentDir)) return; Console.WriteLine($"Deleting Brain {i}..."); const int maxRetries = 3; int retryCount = 0; bool deleted = false; while (!deleted && retryCount < maxRetries) { try { File.SetAttributes(CurrentDir, FileAttributes.Normal); foreach (var dir in Directory.GetDirectories(CurrentDir)) File.SetAttributes(dir, FileAttributes.Normal); foreach (var file in Directory.GetFiles(CurrentDir)) File.SetAttributes(file, FileAttributes.Normal); Directory.Delete(CurrentDir, true); deleted = true; } catch (IOException) { retryCount++; Thread.Sleep(500); Console.WriteLine($"Retrying delete Brain {i} (attempt {retryCount})..."); } } if (!deleted) Console.WriteLine($"Failed to delete Brain {i} after {maxRetries} attempts."); }修复线程管理逻辑的漏洞
StartThreads中轮询ThreadState的方式不可靠,线程可能处于WaitSleepJoin等中间状态,建议用Thread.Join()等待线程完成,避免索引错位的问题。
内容的提问来源于stack exchange,提问作者Golden_Eagle
相关产品推荐
相关产品推荐

