C#使用File.ReadLines读取文件后被锁定 无法通过StreamWriter写入
问题原因
File.ReadLines返回的是延迟求值的IEnumerable<string>类型,并不会在调用时立刻读取所有内容到内存、释放文件句柄,只有当你遍历枚举该返回值的时候才会实际打开文件读取行数据- 你将该延迟枚举对象存储为全局变量,后续
saveBtn_Click中调用lines.ElementAt(0)时会再次触发枚举、重新打开文件读取内容,和当前要执行的写入操作争抢文件锁,导致报错 - 未做托管资源的可靠释放,
StreamWriter未使用using语法包裹,若写入过程中出现异常未执行Close(),也会导致文件锁长期被占用
解决步骤
- 读取文件时立刻将所有行加载到内存,释放文件锁:将
IEnumerable<string>类型的lines改为List<string>,调用File.ReadLines后追加.ToList()立刻完成枚举,或者直接使用File.ReadAllLines方法(该方法会直接返回string[],读取完成立刻释放文件) - 所有IO操作类使用
using语句包裹,确保异常场景下也能正常释放资源、解除文件锁
修改后代码示例
// 把全局变量类型改为List<string> List<String> lines; private void loadCfg() { string cfgPath = Application.StartupPath + @"\server.cfg"; // 加ToList()立刻加载所有行到内存,读取完成直接释放文件 lines = File.ReadLines(cfgPath).ToList(); foreach (var line in lines) { if (line.Contains("Port")) { portTxtBox.Text = extractValue(line); } if (line.Contains("Cars")) { maxCarsCombo.Text = extractValue(line); } if (line.Contains("MaxPlayers")) { maxPlayerCombo.Text = extractValue(line); } } } private void saveBtn_Click(object sender, EventArgs e) { string cfgPath = Application.StartupPath + @"\server.cfg"; // 用using包裹StreamWriter,用完自动释放资源,不需要手动调用Close using (StreamWriter sw = new StreamWriter(cfgPath, false)) { sw.WriteLine(lines.ElementAt(0)); } }
补充说明
如果配置文件体积很小,也可以直接用File.ReadAllLines替换File.ReadLines,效果和加.ToList()完全一致:
lines = File.ReadAllLines(cfgPath).ToList();
内容的提问来源于stack exchange,提问作者Smoking Diesel GR
相关产品推荐
相关产品推荐

