using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; public class FileTimestampAndSizeWatcher { private readonly string _filePath; private DateTime _lastModifiedTime; private long _lastFileSize; public static long _lastReadPosition; private Timer _pollingTimer; private FileSystemWatcher _watcher; public event Action OnFileUpdated; private readonly ConcurrentQueue _logQueue = new ConcurrentQueue(); private readonly AutoResetEvent _logEvent = new AutoResetEvent(false); private bool _isConsuming = false; private readonly int _maxQueueSize = 1000000; // 璁剧疆鏈€澶ч槦鍒楀ぇ灏? private readonly int _maxRetries = 5; // 鏈€澶ч噸璇曟鏁? private readonly int _retryDelay = 1000; // 閲嶈瘯闂撮殧锛屽崟浣嶏細姣 public FileTimestampAndSizeWatcher(string filePath) { _filePath = filePath; _lastModifiedTime = File.GetLastWriteTime(_filePath); _lastFileSize = new FileInfo(_filePath).Length; // 鍚姩鏃朵粠澶村紑濮嬭鍙? _lastReadPosition = 0; } public void Start() { // 鍚姩鏃跺垱寤哄垵濮嬬殑 FileSystemWatcher CreateWatcher(); //鍚敤鏃ュ織娑堣垂 StartLogConsumer(); // 鍒濆璇诲彇鏂囦欢鎵€鏈夊唴瀹? string initialContent = ReadFileContent(); ProcessLogContent(initialContent); // 璁剧疆瀹氭椂鍣紝姣忓垎閽熷埛鏂颁竴娆?FileSystemWatcher _pollingTimer = new Timer(RefreshWatcher, null, TimeSpan.Zero, TimeSpan.FromMinutes(1)); } private void CreateWatcher() { // 鍒涘缓鏂扮殑 FileSystemWatcher 瀹炰緥 _watcher = new FileSystemWatcher(Path.GetDirectoryName(_filePath)) { Filter = Path.GetFileName(_filePath), NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size }; // 娉ㄥ唽浜嬩欢澶勭悊绋嬪簭 _watcher.Changed += OnChanged; // 鍚姩鐩戝惉 _watcher.EnableRaisingEvents = true; } private void RefreshWatcher(object state) { try { // 绂佺敤鐜版湁鐨?FileSystemWatcher锛堝彧鏄仠姝㈣Е鍙戜簨浠讹紝瀹炰緥渚濈劧瀛樺湪锛? _watcher.EnableRaisingEvents = false; // 閲婃斁鐜版湁鐨?FileSystemWatcher 瀹炰緥 _watcher.Dispose(); // 閲嶆柊鍒涘缓 FileSystemWatcher锛屽苟閲嶆柊娉ㄥ唽浜嬩欢澶勭悊绋嬪簭 CreateWatcher(); } catch (Exception ex) { RainOpsMini.Helpers.RainOpsLog.Log($"鍒锋柊 FileSystemWatcher 鏃跺彂鐢熷紓甯? {ex.Message}"); } } private string ReadFileContent() { string newContent = string.Empty; for (int retries = 0; retries < _maxRetries; retries++) { try { // 浣跨敤 FileStream 浠ュ彧璇诲拰鍏变韩璇诲彇鍐欏叆鐨勬ā寮忔墦寮€鏂囦欢 using (var stream = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { stream.Seek(_lastReadPosition, SeekOrigin.Begin); using (var reader = new StreamReader(stream)) { newContent = reader.ReadToEnd(); _lastReadPosition = stream.Position; // 鏇存柊璇诲彇浣嶇疆 } } break; // 鎴愬姛璇诲彇鏂囦欢鍚庤烦鍑洪噸璇? } catch (IOException ex) { // 璁板綍姣忔閲嶈瘯澶辫触鐨勪俊鎭? if (retries == _maxRetries - 1) { throw; // 濡傛灉閲嶈瘯瓒呰繃鏈€澶ф鏁帮紝鎶涘嚭寮傚父 } Thread.Sleep(_retryDelay); // 绛夊緟涓€娈垫椂闂村悗閲嶈瘯 } } return newContent; } private void OnChanged(object sender, FileSystemEventArgs e) { try { DateTime currentModifiedTime = File.GetLastWriteTime(_filePath); long currentFileSize = new FileInfo(_filePath).Length; if (currentFileSize < _lastReadPosition) { _lastReadPosition = 0; } if (currentModifiedTime != _lastModifiedTime || currentFileSize != _lastFileSize) { _lastModifiedTime = currentModifiedTime; _lastFileSize = currentFileSize; string newContent = ReadFileContent(); // 璋冪敤鏂扮殑鏂囦欢璇诲彇鏂规硶 ProcessLogContent(newContent); } } catch (IOException ex) { } } private void ProcessLogContent(string content) { if (!string.IsNullOrWhiteSpace(content)) { var logs = content .Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries) .ToList(); foreach (var log in logs) { if (_logQueue.Count >= _maxQueueSize) { // 涓㈠純鏈€鑰佺殑鏃ュ織 _logQueue.TryDequeue(out _); } _logQueue.Enqueue(log); } _logEvent.Set(); // 閫氱煡娑堣垂鑰呮湁鏂版暟鎹? } } private void StartLogConsumer() { if (_isConsuming) return; _isConsuming = true; Thread consumerThread = new Thread(() => { while (_isConsuming) { while (_logQueue.TryDequeue(out var log)) { try { // 浣跨敤绾跨▼姹犳潵澶勭悊鍥炶皟锛岀‘淇濆洖璋冪殑澶氱嚎绋嬪鐞? ThreadPool.QueueUserWorkItem(state => { try { OnFileUpdated?.Invoke(log); } catch (Exception ex) { } }); } catch (Exception ex) { } } // 鎵归噺澶勭悊鏃ュ織锛岄伩鍏嶉绻佸敜閱? _logEvent.WaitOne(); } }); consumerThread.IsBackground = true; consumerThread.Start(); } public void Stop() { _watcher?.Dispose(); _pollingTimer?.Dispose(); _isConsuming = false; _logEvent.Set(); // 閫€鍑虹嚎绋嬮樆濉? } }