为什么我必须在C#中关闭()一个文件?

Har*_*vey 9 .net c#

我知道这可能看起来很愚蠢,但为什么以下代码只有在我关闭()文件时才有效?如果我不关闭文件,则不会写入整个流.

脚步:

  1. 在表单加载上运行此代码.
  2. 显示后,使用鼠标关闭表单.
  3. 程序终止.

文件对象超出范围时,是否不应自动刷新或关闭?我是C#的新手,但我习惯在C++析构函数中添加对Close()的调用.

// 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();
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 22

C#没有自动确定性清理.如果要控制运行时,必须确保调用清理功能.该using块是这样做的最常见的方式.

如果你没有自己进行清理调用,那么当垃圾收集器决定其他东西需要内存时会发生清理,这可能需要很长时间.

using (StreamWriter outfile = new StreamWriter("../../file.txt")) {
    outfile.Write(b64img);
} // everything is ok, the using block calls Dispose which closes the file
Run Code Online (Sandbox Code Playgroud)

编辑:正如哈维指出的那样,当对象被收集时将尝试进行清理,但这并不能保证成功.为了避免循环引用的问题,运行时不会尝试以"正确"的顺序完成对象,因此FileStreamStreamWriter终结器运行并尝试刷新缓冲输出时实际上已经死了.

如果处理需要清理的对象,请使用using(对于本地作用域)或通过调用IDisposable.Dispose(对于长期对象,例如类成员的指示对象)进行显式处理.

  • @Harvey:在关闭时,运行时会尝试调用任何剩余的终结器(至少在干净关闭期间).你看到了另一个问题.没有对无法到达的对象进行清理的命令,对象图中无法到达的部分中的内部引用被完全忽略以解决循环引用问题.所以可能发生的事情是`StreamWriter`拥有的`FileStream`对象首先处理掉,然后当`StreamWriter`被处理掉并试图刷新它的输出时,就不再有任何地方发送它了. (4认同)

Blu*_*Dog 8

因为Write()被缓冲并且缓冲区被Close()显式刷新.

  • 需要关闭本机文件句柄是更重要的IMO.特别是因为这可以锁定文件,直到最终运行终结器. (2认同)