filemode.append 强制写入位置为文件末尾,仅支持写入(需 fileaccess.write/readwrite),不保证原子性,需配合锁或 streamwriter;streamwriter 构造函数传 true 更简洁;windows 可通过 acl 限制实现系统级只追加。

用 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 就搞定所有安全与一致性需求。追加只是起点,后续的防护、审计、恢复逻辑,才是关键。










