使用StreamWriter和FileStream写入txt文件

24

当我在.NET 4.5中使用StreamWriterFileStream向现有文件追加文本时,我遇到了一件有趣的事情(尚未尝试任何更旧的框架)。我尝试了两种方法,其中一种可行而另一种不可行。我想知道这两种方法之间的区别。

两种方法都包含以下代码

if (!File.Exists(filepath))
    using (File.Create(filepath));

因为我通过个人经验发现,使用 using 语句是确保应用程序完全关闭文件的最佳方式,所以我将创建放在了其中。

非可行方法:

using (FileStream f = new FileStream(filepath, FileMode.Append,FileAccess.Write))
    (new StreamWriter(f)).WriteLine("somestring");

使用这种方法,不会向文件附加任何内容。

工作方法:

using (FileStream f = new FileStream(filepath, FileMode.Append,FileAccess.Write))
    using (StreamWriter s = new StreamWriter(f))
        s.WriteLine("somestring");

我进行了一些谷歌搜索,但不太知道要搜索什么,也没有找到任何有用的信息。那么,为什么匿名的 StreamWriter 失败了,而(非匿名的?命名的?) StreamWriter 却成功了呢?


2
我猜测 StreamWriter 直到被刷新和使用 using 块隐式调用其 Dispose 方法时才会实际 写入 任何内容。编辑:请注意,StreamWriter 有一个 AutoFlush 属性,它可能控制此行为,使其在您编写时自动刷新流,我猜默认情况下是 false - Chris Sinclair
3
这个问题已经被回答过了,但是为什么你想要这样格式化代码呢?在我看来,这样做不仅难以阅读和理解,而且还会增加通过简单格式错误引入 bug 的风险。我是大括号的忠实拥趸 - 永远都是! - TheCodeKing
@TheCodeKing 如果已有答案,您能提供一个链接吗?我实在找了很久每个建议的答案,在发布之前没有看到完全回答它的东西(主要是因为我使用了匿名函数)。而且,我不想就大多数基于风格和偏好的事情进行辩论。在我看来,充斥着实际上并不需要的大括号的代码更难读懂。 - Leon Newswanger
1
@TheCodeKing 但我也在Python中做了大量的工作,因此使用缩进来确定范围已经成为我的第二天性了。 - Leon Newswanger
在这里提到了http://msdn.microsoft.com/en-us/library/system.io.streamwriter.close.aspx,如果未设置AutoFlush,则在Close上发生刷新。由于Dispose关闭流,因此您需要显式调用Dispose或Close以刷新流。 - TheCodeKing
显示剩余5条评论
2个回答

21

听起来似乎您没有清空流。

http://msdn.microsoft.com/en-us/library/system.io.stream.flush.aspx

看起来StreamWriter在写入最终目标(在这种情况下是文件)之前会先将内容写入缓冲区。您还可以设置AutoFlush属性,无需显式刷新即可完成。

http://msdn.microsoft.com/en-us/library/system.io.streamwriter.autoflush.aspx

回答您的问题,当您使用“using”块时,它会调用StreamWriter上的dispose方法,该方法必须进而调用Flush方法。


2
你永远不应该创建实现IDisposable接口的类型的匿名实例。 - xxbbcc
2
我不建议使用AutoFlush并且不释放对象。如果一个对象是可释放的,那么它应该被释放。 - dtb
1
我同意所有评论者的观点,即您应始终处理可丢弃对象。此外,我想回复Leon的“尝试并查看”评论,并说除非明确要求,否则永远不会处理对象。但是,如果它们具有终结器,则会被终止。 - Phillip Scott Givens
2
@PhillipScottGivens 这是正确的,但依赖于终结器并不是一个好的实践。你无法知道它何时运行,因此你也不知道该资源会存在多长时间。 - xxbbcc
1
@PhillipScottGivens 不是想要在这么长时间之后再次提出这个问题,但今天我重新阅读了这个问题,并发现实际上可以在初始化 StreamWriter 时设置 AutoFlush,使用 (new StreamWriter(f) {AutoFlush = true}).WriteLine("somestring")。虽然这仍不是最佳实践,但它是另一种可行且有效的解决方案。 - Leon Newswanger
显示剩余6条评论

7
两个代码片段的区别在于使用了usingusing语句会在块结束时处理对象。 StreamWriter 在写入底层流之前缓冲数据。释放StreamWriter 会刷新缓冲区。如果不刷新缓冲区,则不会写入任何内容。
来自MSDN

您必须调用Close以确保所有数据都正确地写入底层流。

另请参阅:何时应在C#中使用“using”块?

1
不想让您感到麻烦,因为我已经有些假设了,但是您能否添加一些在线查找此信息的参考资料呢?这对他人和我自己都有好处。 - Leon Newswanger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接