如何处理被两个并行库共享、需持续读写的Log.txt文件?
解决多进程共享日志文件的写入与清理冲突问题
核心问题分析
原代码中Parent进程创建FileStream时未指定共享权限,默认会独占文件;Child进程使用File.WriteAllText也会独占文件访问,导致双方互相阻塞抛出文件占用错误。以下是两种可行的解决方案:
方案一:修改文件流共享权限,实现实时读写+清空
Parent进程(持续写入)
将原有的每次写入后关闭流改为持续打开流,并指定FileShare.ReadWrite允许Child进程同时访问:
// 全局持有流对象,避免频繁打开关闭 private static FileStream _logFileStream; private static StreamWriter _logWriter; // 初始化日志写入器(程序启动时调用一次) public static void InitializeLogWriter(string logFilePath) { // 关键:指定FileShare.ReadWrite,允许其他进程读写该文件 _logFileStream = new FileStream( logFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite); _logWriter = new StreamWriter(_logFileStream) { AutoFlush = true }; // 自动刷新避免缓存 } // 写入日志的方法 public static void WriteLogEntry(string strLog) { _logWriter.WriteLine(strLog); } // 程序退出时释放资源 public static void ShutdownLogWriter() { _logWriter?.Dispose(); _logFileStream?.Dispose(); }
Child进程(清理文件)
放弃File.WriteAllText(独占文件),改用FileStream配合SetLength(0)实现安全清空,同时匹配共享权限:
public static void ClearLogFile(string logFilePath) { using (var fileStream = new FileStream( logFilePath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite)) { // 截断文件至0长度,实现清空 fileStream.SetLength(0); fileStream.Flush(); // 立即写入磁盘 } }
方案二:日志轮转机制(更稳定的生产级方案)
如果需要保留历史日志且避免频繁清空的冲突,可采用日志轮转:Child将当前日志文件重命名归档,Parent自动切换到新文件继续写入。
Parent进程(支持自动切换日志文件)
private static string _baseLogPath; private static FileStream _logFileStream; private static StreamWriter _logWriter; public static void InitializeLogWriter(string baseLogPath) { _baseLogPath = baseLogPath; OpenActiveLogFile(); } private static void OpenActiveLogFile() { _logFileStream = new FileStream( _baseLogPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite); _logWriter = new StreamWriter(_logFileStream) { AutoFlush = true }; } public static void WriteLogEntry(string strLog) { // 检查当前日志文件是否被重命名(Child操作),如果不存在则重新创建 if (!File.Exists(_baseLogPath)) { _logWriter.Dispose(); _logFileStream.Dispose(); OpenActiveLogFile(); } _logWriter.WriteLine(strLog); } public static void ShutdownLogWriter() { _logWriter?.Dispose(); _logFileStream?.Dispose(); }
Child进程(归档日志)
public static void ArchiveAndResetLog(string baseLogPath) { if (!File.Exists(baseLogPath)) return; // 生成带时间戳的归档文件名 string archivePath = $"{Path.GetFileNameWithoutExtension(baseLogPath)}_{DateTime.Now:yyyyMMddHHmmss}{Path.GetExtension(baseLogPath)}"; // 重命名当前日志文件(因Parent设置了FileShare.ReadWrite,可正常执行) File.Move(baseLogPath, archivePath); // 此时Parent会自动创建新的日志文件继续写入 }
额外说明
如果需求是删除重复数据而非清空整个文件,可在Child进程中按以下步骤操作:
- 以
FileShare.ReadWrite权限打开文件读取所有内容 - 过滤掉重复的日志条目
- 重新打开文件(或复用现有流),调用
SetLength(0)清空后写入过滤后的内容
内容的提问来源于stack exchange,提问作者Chanikya
相关产品推荐
相关产品推荐

