C#应用程序间歇性出现文件被其他进程占用的异常求助
看起来你遇到了挺头疼的间歇性文件占用问题,作为过来人给你梳理几个实际排查方向,都是踩过的坑,希望能帮到你:
先解决
File.WriteAllText和File.AppendText的衔接冲突
你开头用File.WriteAllText("EventLog_SlagModel.txt", String.Empty);清空日志,这个方法会隐式打开、写入、关闭文件,但如果刚好在这个操作和后面的File.AppendText之间,有其他线程/进程碰了这个文件,就会触发占用异常。而且就算用了using包裹StreamWriter,前面的WriteAllText也可能因为系统IO延迟没完全释放文件锁。
建议把清空和写入合并到同一个StreamWriter操作里,全程用同一个文件流,减少锁冲突的可能:// false参数表示覆盖原文件(等价于清空后写入) using (var sw = new StreamWriter("EventLog_SlagModel.txt", false)) { sw.WriteLine("日志内容"); // 后续需要追加的内容也可以直接在这里写 }排查多线程/外部进程的文件访问干扰
间歇性问题大概率是多线程或者外部进程的锅:- 调试时有没有不小心打开日志文件没关闭?比如用记事本、Notepad++一直打开着,程序再去写入就会报错;
- 你的程序有没有多线程操作这个日志文件?比如后台线程也在写日志却没做同步控制。如果是多线程场景,一定要加
lock块来保证文件访问的原子性:// 定义一个全局锁对象 private static readonly object LogLock = new object(); // 写日志的方法里 lock(LogLock) { using (var sw = new StreamWriter("EventLog_SlagModel.txt", true)) { sw.WriteLine($"[{DateTime.Now}] 日志内容"); } }
优化异常场景下的日志记录逻辑
你提到点击“继续”前日志是空的,可能是异常发生在日志写入之前,或者File.WriteAllText清空了日志但还没来得及写入内容就报错了。建议用try-catch包裹关键代码块,并且在捕获异常时用另一个独立的错误日志文件记录信息,避免原日志被占用导致异常信息丢失:try { File.WriteAllText("EventLog_SlagModel.txt", String.Empty); Code_Triggered = true; this.v_SLAG_DATATableAdapter.Fill(this.bRSDBDataSet.V_SLAG_DATA); using (StreamWriter sw = File.AppendText("EventLog_SlagModel.txt")) { sw.WriteLine("数据填充完成"); } } catch (IOException ex) { // 用独立的错误日志记录异常,避免和业务日志冲突 File.AppendAllText("ErrorLog.txt", $"[{DateTime.Now}] 文件占用异常:{ex.Message}\n堆栈信息:{ex.StackTrace}\n"); // 根据业务需求选择抛出异常或者继续执行 throw; }考虑用成熟日志库替代手写文件操作
如果你不想在文件锁这类细节上浪费时间,不如直接用NLog、Serilog这类成熟的日志库,它们内置了文件访问的同步机制、异常处理、日志滚动等功能,配置也很简单,新手也能快速上手,能帮你规避很多低级的IO问题。
备注:内容来源于stack exchange,提问作者NDionise93

