在日志收集和实时监控系统中,经常需要把服务器上某个文本文件的新增内容实时推送给前端页面或其他服务。用C#可以快速实现一个tail服务,并通过Web API以流式方式把文件追加内容发送出去。

核心实现思路
整体方案分为两部分:一是用FileSystemWatcher监控文件变化,二是通过ASP.NET Core的Controller返回Stream,把新增内容持续写入响应体。
- 使用FileSystemWatcher监听文件Change事件
- 记录上次读取位置,只读取追加部分
- 通过HttpResponse.Body的Stream持续写入数据
文件监控与读取类
下面代码展示一个简易的TailWatcher,负责监听文件并把新增行通过回调抛出。
using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
public class TailWatcher
{
private long _lastPosition;
private readonly string _filePath;
private readonly Action<string> _onAppend;
public TailWatcher(string filePath, Action<string> onAppend)
{
_filePath = filePath;
_onAppend = onAppend;
_lastPosition = new FileInfo(filePath).Length;
}
public void Start()
{
var watcher = new FileSystemWatcher(Path.GetDirectoryName(_filePath), Path.GetFileName(_filePath));
watcher.NotifyFilter = NotifyFilters.Size;
watcher.Changed += (s, e) => ReadAppend();
watcher.EnableRaisingEvents = true;
}
private void ReadAppend()
{
using var fs = new FileStream(_filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
fs.Seek(_lastPosition, SeekOrigin.Begin);
using var reader = new StreamReader(fs, Encoding.UTF8);
string line;
while ((line = reader.ReadLine()) != null)
{
_onAppend(line + Environment.NewLine);
}
_lastPosition = fs.Position;
}
}
Web API实时推送
在ASP.NET Core中,我们可以写一个Controller,用Stream把内容推给客户端。注意要禁用缓冲并保持连接。
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;
[Route("api/tail")]
public class TailController : Controller
{
[HttpGet("{file}")]
public async Task TailFile(string file)
{
Response.ContentType = "text/plain";
Response.Headers["Cache-Control"] = "no-cache";
var path = Path.Combine(Directory.GetCurrentDirectory(), "logs", file);
if (!System.IO.File.Exists(path))
{
Response.StatusCode = 404;
return;
}
var source = new TaskCompletionSource<bool>();
var watcher = new TailWatcher(path, async (text) =>
{
var bytes = System.Text.Encoding.UTF8.GetBytes(text);
await Response.Body.WriteAsync(bytes, 0, bytes.Length);
await Response.Body.FlushAsync();
});
watcher.Start();
// 保持连接直到客户端断开
Context.RequestAborted.Register(() => source.TrySetResult(true));
await source.Task;
}
}
使用建议
如果前端需要双向通信或多人订阅,建议改用SignalR,把TailWatcher的回调Broadcast到Hub连接。对于单纯的文件tail推送,上面的流式API已经足够轻量。
注意:示例中的路径拼接仅用于演示,生产环境必须做权限校验和路径穿越过滤。
小结
通过C#的FileSystemWatcher加ASP.NET Core流式响应,我们可以用很少代码实现一个tail服务,并经由Web API实时推送文件追加内容,避免前端轮询,提升监控效率。