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

时间:2010-10-15 17:41:40

标签: c# .net

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

步骤:

  1. 在表单加载上运行此代码。
  2. 显示后,使用鼠标关闭表单。
  3. 程序终止。
  4. 文件对象超出范围时是不是应该自动刷新或关闭?我是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();
    

6 个答案:

答案 0 :(得分: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
编辑:正如哈维指出的那样,虽然在收集对象时会尝试进行清理,但这并不能保证成功。为了避免循环引用的问题,运行时不会尝试以“正确”的顺序最终确定对象,因此FileStream终结器运行并尝试刷新缓冲时StreamWriter实际上已经死了输出

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

答案 1 :(得分:8)

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

答案 2 :(得分:3)

Streams是“管理”或“处理”非垃圾回收资源的对象。因此,它们(Streams)实现了IDisposable接口,当与'using'一起使用时,将确保清理非垃圾收集的资源。试试这个:

using ( StreamWriter outfile = new StreamWriter("../../file.txt") )
{
   outfile.Write(b64img);
}

如果没有#Close,您无法确定何时正确关闭基础文件句柄。有时,这可以在应用程序关闭。

答案 3 :(得分:2)

因为您正在使用一个流写器,并且在您Close()编写器之前它不会刷新缓冲区。通过将streamwriter的AutoFlush属性设置为true,可以指定希望编写器在每次调用write时进行刷新。

查看文档。 http://msdn.microsoft.com/en-us/library/system.io.streamwriter.aspx

如果你想写一个没有“关闭”的文件,我会用:

System.IO.File

答案 4 :(得分:1)

操作系统缓存写入块设备以使操作系统具有更好的性能。在将写入器设置为autoflush后,通过刷新缓冲区强制写入。

答案 5 :(得分:-2)

因为C#设计师在克服Java而不是C ++,尽管名称不同。

在我看来,他们真的错过了这条船。 。

它甚至不必释放内存更好,只需自动运行终结器或IDisposable方法。