VB.NET多线程追加文件内容遇文件占用错误的解决方法
解决多线程环境下日志文件占用的IOException问题
报错信息:
IOException: The process cannot access the file 'C:\Users\Administrator\source\repos\NSC 6\NSC 6\bin\Debug\net6.0-windows\log\log-latest.log' because it is being used by another process.现有两种VB.NET日志函数实现:
方式1:Function log_record(logtext As String) File.AppendAllText(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) & "\log\log-latest.log", "「" & Now & "」" & logtext) End Function方式2:
Function log_record(logtext As String) Dim log_writer As New StreamWriter(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) & "\log\log-latest.log", True) log_writer.WriteLine("「" & Now & "」" & logtext) log_writer.Close() End Function
核心原因
两种实现均未处理多线程下的文件访问竞争:
File.AppendAllText虽会自动完成打开-写入-关闭流程,但高并发场景下,多个线程可能同时触发文件打开操作,导致权限冲突。StreamWriter方式无同步控制,多线程同时创建实例会争夺文件独占权限;且未使用Using语句,异常场景下可能出现文件句柄泄漏。
解决方法
方法1:使用同步锁(SyncLock)控制文件访问
通过全局锁对象确保同一时间只有一个线程能写入文件,是轻量且直接的解决方案:
' 定义全局静态锁对象,所有线程共用同一锁 Private Shared ReadOnly logLock As New Object() Function log_record(logtext As String) ' 用Path.Combine安全拼接路径,避免格式错误 Dim logDir As String = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "log") Dim logPath As String = Path.Combine(logDir, "log-latest.log") ' 确保日志目录存在,避免目录不存在的异常 Directory.CreateDirectory(logDir) ' 同步锁:同一时间仅一个线程进入代码块 SyncLock logLock ' 方式A:用File.AppendAllText,自动处理打开关闭 File.AppendAllText(logPath, $"「{Now}」{logtext}{Environment.NewLine}") ' 方式B:用StreamWriter+Using,确保资源自动释放 ' Using log_writer As New StreamWriter(logPath, True) ' log_writer.WriteLine($"「{Now}」{logtext}") ' End Using End SyncLock End Function
方法2:使用成熟的线程安全日志库
如果需要更复杂的日志功能(如滚动日志、日志分级、性能优化),可直接使用Serilog或NLog等第三方日志库,这些库内部已原生实现多线程安全的文件写入,无需手动处理同步。
内容的提问来源于stack exchange,提问作者xiaoyululu
相关产品推荐
相关产品推荐

