You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#应用运行时实时查看自定义日志文件的更新?

Real-Time Log Viewing for Your C# Application

Hey Andrew, let's tackle this problem you're having with real-time log viewing while your C# app is running.

First, let's refine your existing logging code to ensure it plays nicely with both external tools and in-app viewers:

Optimized Logging Method

Your current LogSync method is solid, but we can make a couple of tweaks to ensure the file handle is properly released (so external tools can read it without lock issues) and simplify the code a bit:

protected void LogSync(string message) {
    try {
        lock (SynLock) {
            // The using block automatically disposes the StreamWriter, closing the file handle
            using (var sw = new StreamWriter(SyncFilename, true)) {
                sw.WriteLine(message); // Replaces Write + Environment.NewLine for cleaner code
            }
        }
    } catch (Exception e) {
        Console.WriteLine($"Log write failed: {e.Message}");
        throw;
    }
}

Why This Works

The using statement guarantees the StreamWriter is disposed immediately after writing, which releases the file lock. This means tools like:

  • Notepad++ (enable "Reload if changed" in the View menu)
  • PowerShell's Get-Content -Path "your-log-file.txt" -Wait
  • Unix-like tail -f your-log-file.txt (on Linux/macOS/WSL)
    can all monitor the log file in real time as your app writes to it.

Build an In-App Real-Time Log Viewer

If you want to add a dedicated log viewer directly into your C# app (e.g., a text box that updates as logs are written), you can use FileSystemWatcher to monitor the log file and display new content automatically. Here's a step-by-step implementation:

Step 1: Declare Required Variables

Add these fields to your form/class:

private FileSystemWatcher _logFileWatcher;
private long _lastReadPosition = 0;
private readonly object _uiUpdateLock = new object();

Step 2: Initialize the File Watcher

Call this method when your app starts (e.g., in Form_Load for WinForms):

private void InitializeLogViewer() {
    var logDirectory = Path.GetDirectoryName(SyncFilename);
    var logFileName = Path.GetFileName(SyncFilename);

    _logFileWatcher = new FileSystemWatcher(logDirectory, logFileName) {
        NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.Size,
        EnableRaisingEvents = true
    };

    // Hook up the event handler for file changes
    _logFileWatcher.Changed += OnLogFileUpdated;

    // Load existing log content on startup
    if (File.Exists(SyncFilename)) {
        var fileInfo = new FileInfo(SyncFilename);
        _lastReadPosition = fileInfo.Length;
        var initialLogs = File.ReadAllText(SyncFilename);
        UpdateLogDisplay(initialLogs);
    }
}

Step 3: Handle File Change Events

This method reads only the new content added since the last check:

private void OnLogFileUpdated(object sender, FileSystemEventArgs e) {
    // FileSystemWatcher can fire multiple events for one write—add a small delay to avoid duplicates
    Thread.Sleep(100);
    
    var fileInfo = new FileInfo(e.FullPath);
    if (fileInfo.Length <= _lastReadPosition) return;

    try {
        // Open the file with shared read/write access to avoid locking conflicts
        using (var stream = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        using (var reader = new StreamReader(stream)) {
            // Jump to the last position we read
            reader.BaseStream.Seek(_lastReadPosition, SeekOrigin.Begin);
            var newLogContent = reader.ReadToEnd();
            
            // Update our last read position
            _lastReadPosition = reader.BaseStream.Position;
            
            // Update the UI with new content
            UpdateLogDisplay(newLogContent);
        }
    } catch (IOException) {
        // Retry if the file was temporarily locked by the logging method
        Thread.Sleep(500);
        OnLogFileUpdated(sender, e);
    }
}

Step 4: Update the UI

This method ensures we update the UI safely from the main thread (critical for WinForms/WPF):

private void UpdateLogDisplay(string newContent) {
    // For WinForms: Check if we need to marshal to the UI thread
    if (yourLogTextBox.InvokeRequired) {
        yourLogTextBox.Invoke(new Action<string>(UpdateLogDisplay), newContent);
        return;
    }

    lock (_uiUpdateLock) {
        yourLogTextBox.AppendText(newContent);
        // Auto-scroll to the bottom of the text box
        yourLogTextBox.SelectionStart = yourLogTextBox.Text.Length;
        yourLogTextBox.ScrollToCaret();
    }
}

Step 5: Clean Up the Watcher

Don't forget to dispose the watcher when your app closes:

private void OnApplicationClosing(object sender, EventArgs e) {
    _logFileWatcher?.Dispose();
}

Key Notes

  • Avoid Duplicate Events: The small Thread.Sleep in OnLogFileUpdated helps prevent multiple UI updates for a single log write.
  • Shared File Access: Using FileShare.ReadWrite ensures your log viewer can read the file even while the logging method is writing to it.
  • Thread Safety: Always marshal UI updates to the main thread to avoid cross-thread exceptions.

内容的提问来源于stack exchange,提问作者Andrew Simpson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:46:52