是否需关闭FileStream的子流?仅关闭FileStream是否足够?
问题背景
我查阅了许多关于C#流的资料,但未找到符合自身场景的解决方案。出于学习目的,我实现了一个基于文件的JSON列表数据库类:
public sealed class JSONBD<T> : IDisposable { private FileStream fileStream; private TextWriter textWriter; // textWriter = new StreamWriter(fileStream) private TextReader textReader; // textReader = new StreamReader(fileStream) public List<T> Bd { get; set; } // null is not available here public string FilePath { get; } public void Open(); public void Commit(); public void Close(); }
我尝试使用System.IO流以确保文件仅被当前实例使用。由于对象生命周期内需要多次执行提交操作,无法使用using语句——因为提交时StreamWriter会关闭FileStream,反序列化文件后StreamReader也会关闭FileStream。
于是我决定同时使用一个FileStream、一个StreamWriter和一个StreamReader对象。现在有两个问题:
- 这种基于同一个FileStream创建两个流的方式是否正确?
- 该如何关闭这些流?仅调用FileStream.Close()是否足够?我查阅的资料中仅提及关闭底层流,但我有两个上层流,是否需要将两者都关闭?但其中一个关闭时就会关闭FileStream了。
问题解答
1. 复用同一个FileStream创建读写流是否正确?
这种做法并不推荐,会引发不可预期的问题:
- StreamReader和StreamWriter各自维护独立的缓冲区与文件位置指针,同时操作同一个底层FileStream时,会互相干扰读写位置,导致数据错乱。比如写入后读取的内容可能不是最新的,或者读取到错误的位置。
- 即使StreamWriter会自动Flush缓冲区,双流共存时的同步逻辑会变得复杂,极易出现数据不一致。
更合理的处理方式:
- 读取操作:每次单独打开FileStream创建StreamReader,读取完成后关闭所有流;
- 提交(写入)操作:每次单独打开FileStream创建StreamWriter,写入完成后关闭所有流;
- 要确保文件独占访问,打开FileStream时指定
FileShare.None参数,阻止其他进程或实例同时访问该文件。
如果必须在实例生命周期内保持FileStream打开,那要避免同时创建读写双流,而是按需动态创建其中一个,且构造时传入leaveOpen: true参数,确保上层流Dispose时不关闭底层FileStream:
// 写入示例 var writer = new StreamWriter(fileStream, leaveOpen: true); writer.Write("要写入的内容"); writer.Flush(); // 确保缓冲区数据写入底层流 writer.Dispose(); // 仅释放writer自身资源,不关闭fileStream // 读取示例 var reader = new StreamReader(fileStream, leaveOpen: true); var content = reader.ReadToEnd(); reader.Dispose(); // 仅释放reader自身资源,不关闭fileStream
2. 流的正确关闭方式
- 若上层流(StreamReader/StreamWriter)构造时未指定
leaveOpen: true,调用它们的Close()或Dispose()会自动关闭底层FileStream,此时再操作FileStream或另一个上层流会触发ObjectDisposedException。 - 若指定了
leaveOpen: true,上层流Dispose仅释放自身资源,不会关闭底层FileStream,需手动关闭FileStream。
针对你的类,正确的清理步骤:
- 先依次Dispose已创建的StreamReader和StreamWriter,确保缓冲区数据被Flush并释放上层流资源;
- 最后Dispose底层的FileStream。
由于你的类实现了IDisposable,应该在Dispose()方法中完成这些清理工作,而非依赖手动调用Close():
public void Dispose() { textReader?.Dispose(); textWriter?.Dispose(); fileStream?.Dispose(); }
即使其中一个上层流已经关闭了底层流,调用其他流的Dispose也不会报错(Dispose方法是幂等的),所以按顺序释放所有资源是安全的。
内容的提问来源于stack exchange,提问作者VladisS
相关产品推荐
相关产品推荐

