File.AppendAllText是C#内置轻量日志方案,需手动添加时间戳、换行及路径处理;多线程下须用TextWriter.Synchronized或加锁;大文件需手动轮转;结构化日志可临时重定向Console输出。

用 File.AppendAllText 写日志最直接,但得手动加时间戳和换行
不需要引入第三方库,File.AppendAllText 是 C# 自带的轻量方案。它会自动创建文件、追加内容、处理编码(默认 UTF-8),适合记录简单操作事件,比如按钮点击、配置加载成功这类低频动作。
常见错误是直接写 File.AppendAllText("log.txt", "用户登录") —— 没时间戳、没换行,多条日志挤成一行,查起来费劲。
- 每次写入前拼上
DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") - 结尾固定加
\r\n,避免后续日志粘连 - 路径建议用
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt"),防止部署后找不到位置
File.AppendAllText(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log.txt"),
$"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] 用户登录成功\r\n");多线程下直接写文件会崩,得加锁或改用 TextWriter.Synchronized
如果程序有后台任务、定时器或多个窗体同时调用日志,File.AppendAllText 会抛出 IOException:“进程无法访问该文件,因为另一个进程正在使用它”。这不是权限问题,是并发写入冲突。
最省事的解法不是自己写 lock,而是用 .NET 自带的线程安全包装:
- 把
StreamWriter实例缓存为静态字段,初始化时传入File.AppendText(path) - 再用
TextWriter.Synchronized包一层,之后所有WriteLine都自动串行 - 别忘了在程序退出前调用
Dispose(),否则最后一段日志可能没刷到磁盘
private static readonly TextWriter _logWriter =
TextWriter.Synchronized(File.AppendText("log.txt"));
<p>// 使用时
_logWriter.WriteLine($"[{DateTime.Now:O}] 数据保存完成");</p><p>// 退出前(例如 MainForm.FormClosing)
_logWriter?.Dispose();日志文件越来越大?得手动轮转,.NET 没内置滚动策略
File.AppendAllText 和 StreamWriter 都不会自动切分文件。跑几天后 log.txt 可能到几百 MB,用记事本打不开,File.ReadAllLines 加载直接卡死。
简单轮转逻辑不难实现,关键是触发时机和命名规则要稳:
- 每次写入前检查当前文件大小,超 10MB 就重命名成
log_20240520_152342.txt格式(含时间戳) - 新日志永远写入
log.txt,旧文件不删,靠日期区分 - 别用
File.GetCreationTime判断是否该切分——文件复制后这个时间会变,只信Length
注意:切分动作本身也有并发风险,所以轮转逻辑必须包在同一个 lock 块里,和写入共用一把锁。
想结构化记录(比如带等级、线程ID)?Console.WriteLine + 重定向是临时捷径
如果只是临时调试,又不想装 NLog 或 Serilog,可以把日志输出重定向到文件,还能顺便带上 Thread.ManagedThreadId 这类信息:
- 在
Main方法开头加Console.SetOut(new StreamWriter("debug.log") { AutoFlush = true }); - 之后所有
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] [T{Thread.CurrentThread.ManagedThreadId}] {msg}")都进文件 - 好处是天然线程安全(
StreamWriter内部锁了),坏处是没法单独控制日志级别,所有Console.Write都会进去
这招适合快速验证逻辑流,上线前还是得换成更可控的方式。
真正麻烦的从来不是“怎么写进去”,而是“怎么不让它拖慢主线程”“怎么保证断电时不丢最后几条”“怎么让运维能一眼看出哪条是异常堆栈”——这些得靠异步队列、缓冲区、异常捕获包裹,不是加个 File.AppendAllText 就完事的。








