为什么我必须在C#中关闭()文件?
我知道这可能看起来很傻,但为什么只有在关闭()文件时,下面的代码才起作用?如果不关闭该文件,则不会写入整个流 步骤:为什么我必须在C#中关闭()文件?,c#,.net,C#,.net,我知道这可能看起来很傻,但为什么只有在关闭()文件时,下面的代码才起作用?如果不关闭该文件,则不会写入整个流 步骤: 在表单加载时运行此代码 显示表单后,使用鼠标关闭表单 程序终止 文件对象不应该在超出范围时自动刷新或关闭吗?我是C语言的新手,但是我习惯于在C++析构函数中添加对CULL()的调用。 // Notes: complete output is about 87KB. Without Close(), it's missing about 2KB at the end. // Co
// Notes: complete output is about 87KB. Without Close(), it's missing about 2KB at the end.
// Convert to png and then convert that into a base64 encoded string.
string b64img = ImageToBase64(img, ImageFormat.Png);
// Save the base64 image to a text file for more testing and external validation.
StreamWriter outfile = new StreamWriter("../../file.txt");
outfile.Write(b64img);
// If we don't close the file, windows will not write it all to disk. No idea why
// that would be.
outfile.Close();
因为Write()是缓冲区,而Close()会显式刷新缓冲区。操作系统缓存写块设备,以使操作系统具有更好的性能。将streamwriter设置为autoflush写入后,通过刷新缓冲区强制写入 C#没有自动确定性清理功能。如果要控制清理函数的运行时间,必须确保调用该函数。使用块的
是最常用的方法
如果您自己没有加入cleanup调用,那么当垃圾回收器决定其他事情需要内存时,就会发生cleanup,这可能需要很长时间
using (StreamWriter outfile = new StreamWriter("../../file.txt")) {
outfile.Write(b64img);
} // everything is ok, the using block calls Dispose which closes the file
编辑:正如Harvey指出的,虽然收集对象时会尝试清理,但这并不能保证成功。为了避免循环引用的问题,运行时不会尝试以“正确”的顺序完成对象,因此当StreamWriter
终结器运行并尝试刷新缓冲输出时,FileStream
实际上可能已经死了
如果处理需要清理的对象,请使用或调用IDisposable.Dispose
(对于本地范围的使用)显式地进行清理。流是“管理”或“处理”非垃圾收集资源的对象。因此,它们(流)实现IDisposable接口,当与“using”一起使用时,该接口将确保清理非垃圾收集的资源。试试这个:
using ( StreamWriter outfile = new StreamWriter("../../file.txt") )
{
outfile.Write(b64img);
}
如果没有#Close,则无法确定底层文件句柄何时会正确关闭。有时,这可能是在APP关机。因为C++设计人员是克隆java而不是C++,尽管名称是.<
在我看来,他们真的错过了机会。C++在范围出口上的风格破坏会更好。
它甚至不需要释放内存,只需自动运行finalizer或IDisposable方法。因为您使用的是streamwriter,它在您关闭写入程序之前不会刷新缓冲区。通过将streamwriter的AutoFlush
属性设置为true,可以指定希望写入程序在每次调用write时刷新
查看文档
如果要在不“关闭”的情况下写入文件,我将使用:
System.IO.File
或者通过显式调用Flush()。在我看来,需要关闭本机文件句柄更为重要。特别是因为这样可以锁定文件,直到最终运行终结器。仍然不会关闭文件,大多数程序都不能打开它直到第一个程序关闭它。你可能会发现讨论有助于解释C++和C++之间的差异。一般来说,我将使用C++ {析构函数(C)+ <代码> > IDISPABLE < /COD>和<代码>,使用{} < /Cord>。当然,使用
比显式调用Close
或Dispose
更安全,因为它将调用包装在try finally
块中,以确保对象已被处理。谢谢大家,提供了清晰、快速的帮助。-1:抱怨语言有缺陷并没有真正的帮助,尤其是抱怨“C#是Java的一个副本,这就是它像Java一样工作的原因。“这是一个经过深思熟虑的设计决策,它与C#中垃圾收集的工作方式有关。请参阅以了解为什么自动处理不起作用的解释。我不是投反对票的人,但在6k rep,您现在应该知道如何留下评论了。这不是答案。顺便说一句,您想要的确实存在,它被称为C++/CLI,.NET,支持RAII并在作用域末尾自动调用析构函数。类C{Stream s;void M(){s s2=OpenAStream();this.s=s2;}}}-您的想法是,当s2超出作用域时,应该自动释放流,即使这个.s仍然有引用?你不认为这会让人们感到惊讶吗?这可能不是答案,但它加上它产生的评论信息量很大。如果C?C在中间的某个地方遇到了,当最后一个引用超出范围时,该对象如何处理?@哈维:引用计数的问题是循环引用。因此,C语言团队完全放弃了这个问题,而不是试图解决无循环参考案例。我想只有在某些时候解决这个问题才违反了“最小意外”的原则,所以我不想太强烈地反对他们的决定。事实上,如果他们只是让使用
块静默地对非一次性类型不做任何事情,而不是生成编译器错误,我会非常高兴。顺便说一句,当您注意到实现了IDisposable
的对象时,您应该使用使用
,除非你不想马上清理对象(例如,如果它是一个成员变量,你可能想在以后的代码< >处理/代码>)。想象一下C++必须清理所有的东西……斯卡里猜想我不知道的是,除非我关闭,否则清理功能永远不会被调用。似乎当我终止程序时,它没有对任何需要处理的对象运行清理,而是在没有垃圾收集的情况下终止。@Spooks,是的,它是。。。在C++中,有10或几年的C++是没有“删除”的。正如这个问题所示,这并不是完全没有根据的。@Harvey:在关机时,运行时会尝试调用任何剩余的终结器(在