优先用 StreamReader/StreamWriter 读写 TXT 文件;编码不匹配易致乱码,推荐统一 UTF-8 或显式指定 GBK;ReadLine() 返回 null 仅表示文件末尾;StreamWriter 默认覆盖,追加需传 true;小文件用 File 类静态方法更安全。

StreamReader 和 FileStream 不是同一层的东西,直接混用容易出错。读写 TXT 文件,优先用 StreamReader/StreamWriter,而不是裸露操作 FileStream —— 除非你明确需要控制字节流、缓冲区或共享底层流。
StreamReader 读取文件时编码不匹配导致乱码
Windows 默认记事本保存的 ANSI 编码(如 GBK)和 C# 默认的 UTF-8 不兼容,StreamReader 不显式指定编码时会按 UTF-8 解码,中文就变问号或方块。
- 用
File.ReadAllText(filepath, Encoding.Default)快速适配系统默认编码(但不跨平台) - 更稳妥:统一用 UTF-8 并确保文件本身是 UTF-8 编码(记事本另存为 → “UTF-8”)
- 若必须读 ANSI 文件,用
new StreamReader(filepath, Encoding.GetEncoding("GBK")) -
Encoding.UTF8是推荐首选;Encoding.Default在不同机器上可能行为不一致
StreamReader.ReadLine() 返回 null 的真实含义
ReadLine() 返回 null 只表示“已到文件末尾”,不代表读取失败或异常。它不是错误信号,而是正常流程终点。
- 不要在
while (line != null)外再加一层if (line == null) break;—— 多余 - 空行(即内容为空字符串
"")会被正常返回,不会被跳过 - 最后一行若没换行符,
ReadLine()仍能读到该行内容,之后才返回null - 如果文件为空,第一次调用
ReadLine()就返回null
StreamWriter 写入时覆盖还是追加?看构造函数参数
StreamWriter 默认覆盖文件内容,要追加必须显式传 true 作为第二个参数。
- 覆盖写:
new StreamWriter("log.txt")或new StreamWriter("log.txt", false) - 追加写:
new StreamWriter("log.txt", true) - 使用
using语句时,务必确认是否要保留旧内容 —— 错写成覆盖会导致日志丢失 - 追加模式下,即使文件不存在也会自动创建,无需提前判断
File 类静态方法 vs StreamReader/StreamWriter 实例化
简单场景用 File.ReadAllLines、File.WriteAllText 更安全;大文件或需逐行处理逻辑时才手动管理 StreamReader。
-
File.ReadAllLines一次性加载全部行到内存,适合小文件( -
File.ReadLines返回IEnumerable<string></string>,延迟执行,适合遍历但不全载入 - 手动 new
StreamReader要自己Dispose(推荐用using),否则文件句柄泄漏 -
File.WriteAllText内部已用 UTF-8,等价于new StreamWriter(path, false, Encoding.UTF8)
实际开发中,最易忽略的是编码一致性与资源释放时机 —— 尤其在日志写入、配置读取这类高频操作里,一个没关的 StreamWriter 可能让后续写入失败,而乱码问题常被误判为文件损坏。


















