Files
squad-rain-ops-mini/Helpers/SquadGameLog/FileTimestampAndSizeWatcher.cs

222 lines
6.9 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<string> OnFileUpdated;
private readonly ConcurrentQueue<string> _logQueue = new ConcurrentQueue<string>();
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(); // 閫€鍑虹嚎绋嬮樆濉?
}
}