StreamWriter报错文件被其他进程占用,疑因读写及开关频率过高
解决StreamWriter高频调用时“文件被其他进程占用”的问题
嘿,这个坑我之前踩过!当你高频调用writeLog方法写日志时,确实会因为文件打开/关闭的速度跟不上调用频率,导致前一次的文件流还没完全释放,下一次就尝试打开同一个文件,触发“文件被其他进程占用”的错误。
问题根源
你原来的代码每次调用writeLog都会新建一个StreamWriter实例,哪怕用了using语句确保释放,短时间内多次调用时,操作系统的文件系统可能还没完成文件的解锁操作,下一次打开请求就来了,直接造成冲突。
最优解决方案:复用StreamWriter实例
我们可以把StreamWriter做成静态实例,保持文件打开状态直到程序退出再关闭,这样既避免了频繁打开/关闭文件的开销,也从根本上解决了占用冲突问题。同时要加上线程锁,确保多线程调用时的安全性。
修改后的代码示例:
private static StreamWriter _logWriter; private static readonly object _logLock = new object(); public static void writeLog(string msg) { lock (_logLock) { if (_logWriter == null) { // 构建日志目录和文件路径 string currentMonth = DateTime.Now.ToString("MMM"); string currentYear = DateTime.Now.ToString("yyyy"); string directoryName = Path.Combine(@"C:\AutoSkill\LogFiles", $"{currentMonth}-{currentYear}"); // 直接创建目录,已存在的话不会报错 Directory.CreateDirectory(directoryName); string logFileName = $"Log_{DateTime.Now:yyyyMMdd}.txt"; string logFilePath = Path.Combine(directoryName, logFileName); // 以追加模式打开文件,设置自动刷新缓冲区 _logWriter = new StreamWriter(logFilePath, true, Encoding.UTF8) { AutoFlush = true }; } // 写入带时间戳的日志内容 _logWriter.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {msg}"); } } // 记得在程序退出时释放资源(比如控制台Main末尾、WinForm的FormClosing事件) public static void CloseLogWriter() { lock (_logLock) { _logWriter?.Flush(); _logWriter?.Close(); _logWriter?.Dispose(); _logWriter = null; } }
关键细节说明
- 静态实例+锁:静态实例保证整个应用生命周期内只打开一次文件,线程锁避免多线程同时写入导致的异常或日志乱序。
- AutoFlush = true:确保日志内容立即写入文件,而不是留在缓冲区,避免程序意外退出时丢失日志。
- Directory.CreateDirectory:不用提前判断目录是否存在,这个方法会自动处理已存在的情况,简化代码逻辑。
备选方案(不推荐高频场景)
如果实在不想复用实例,也可以用File.AppendAllText,但它本质还是每次调用都打开/关闭文件,高频调用下依然可能出现占用问题,代码示例:
private static readonly object _logLock = new object(); public static void writeLog(string msg) { string currentMonth = DateTime.Now.ToString("MMM"); string currentYear = DateTime.Now.ToString("yyyy"); string directoryName = Path.Combine(@"C:\AutoSkill\LogFiles", $"{currentMonth}-{currentYear}"); Directory.CreateDirectory(directoryName); string logFilePath = Path.Combine(directoryName, $"Log_{DateTime.Now:yyyyMMdd}.txt"); string logContent = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {msg}{Environment.NewLine}"; // 加锁避免多线程写入冲突 lock (_logLock) { File.AppendAllText(logFilePath, logContent, Encoding.UTF8); } }
这个方案在低频率调用时没问题,但高频场景下还是推荐复用StreamWriter的方式,性能和稳定性都更优。
内容的提问来源于stack exchange,提问作者Ben R
相关产品推荐
相关产品推荐

