用 FileMode.Append
打开文件时,写入位置自动跳转到末尾
这是最直接的方式:只要用
FileMode.Append打开文件流,系统会强制将写入位置设为文件末尾,无论你之前是否调用过
Seek()或设置了
Position。注意,
Append模式只允许写入,不支持读取(除非额外指定
FileAccess.ReadWrite,但那样就失去“只追加”语义了)。
常见错误是误以为
FileMode.Append+
FileAccess.Read可行——这会抛出
System.ArgumentException: 'Access to the path is denied.'。必须搭配
FileAccess.Write或
FileAccess.ReadWrite。
FileStream fs = new FileStream("log.txt", FileMode.Append, FileAccess.Write, FileShare.Read) —— 安全、典型用法
若需写完立刻刷盘,记得调用 fs.Flush();否则依赖缓冲,崩溃时可能丢最后几条日志 多线程写同一文件时,
FileMode.Append本身不保证原子性,需外加
lock或用
StreamWriter配合
TextWriter.Synchronized
用 StreamWriter
构造函数传 true
启用追加模式
StreamWriter的构造函数第二个布尔参数为
true时,底层自动使用
FileMode.Append和
FileAccess.Write,行为一致但更简洁。它还会自动处理编码和换行符,适合文本日志场景。
容易忽略的是:如果文件不存在,
StreamWriter会自动创建;但若目录不存在,会抛出
DirectoryNotFoundException,得提前用
Directory.CreateDirectory()。
using var sw = new StreamWriter("data.log", true) { AutoFlush = true } —— 推荐加 AutoFlush = true避免缓冲丢失 不要手动调用
sw.BaseStream.Seek(),即使成功也不会改变后续
WriteLine()的行为——它始终追加 避免在循环里反复新建
StreamWriter实例,频繁打开/关闭文件影响性能;应复用实例或用对象池
Windows 上通过 ACL 限制写权限实现系统级只追加
仅靠 .NET 流模式无法阻止其他进程或用户用记事本、PowerShell 等工具修改文件中间内容。真要 enforce “只能追加”,得结合 Windows 文件系统权限(ACL):移除用户的
Modify权限,只保留
WriteData(即追加)和
ReadData。
这需要管理员权限,且仅适用于 NTFS。代码中可用
FileSecurity类操作,但要注意:设置 ACL 后,普通用户调用
File.WriteAllText()会直接失败,而
FileMode.Append仍可成功——这才是你想要的效果。 用
File.GetAccessControl()获取当前 ACL,再用
SetAccessRule()移除
FileSystemRights.Modify务必保留
FileSystemRights.AppendData,否则
FileMode.Append也会被拒绝 Linux/macOS 不支持该机制,跨平台方案只能靠外部守护进程或专用日志服务(如 systemd-journald)
注意 FileMode.Append
不等于“不可覆盖”
追加模式下,你不能指定偏移写入,但仍有几个边界情况可能导致非末尾写入:一是用
FileStream的
Write()写入长度为 0 的字节数组(无副作用);二是文件被其他进程截断(
SetLength(0)),此时下次追加会从新末尾(即开头)开始——这不是 .NET 的 bug,而是底层 OS 行为。
所以真正的只追加日志系统,通常还需配合:文件名带时间戳防重名、定期归档压缩、用独立进程监控文件大小突变、或改用内存映射文件(
MemoryMappedFile)+ 自定义写入协议。
别指望单靠一个 FileMode 就搞定所有安全与一致性需求。追加只是起点,后续的防护、审计、恢复逻辑,才是关键。
