之前打开文件流后总不记得关闭流,昨天终于出现问题了,因此上网搜了一下,下面是实际操作和网上搜索后的记录:
1.关闭流的顺序一般为后开先关,如
1 Image img = Image.FromFile("file.jpg");
2 MemoryStream ms = new MemoryStream();
3 img.Save(ms, ImageFormat.Jpeg);
4 ms.Close();
5 ms.Dispose();
6 img.Dispose();
其实不用如此。因为是深拷贝,所以ms和img之间已经没有联系了,两个对象是以不同的形式操作同一个文件,所以先关闭哪一个都没关系。下面的例子可以证明一个对象关闭了,而另一个对象依然可以操作该文件。注意这两个对象属于同一个进程来操作文件,所以不会产生IOException。
1 Image img = Image.FromFile("file.jpg");
2 MemoryStream ms = new MemoryStream();
3 img.Save(ms, ImageFormat.Jpeg);
4 img.Dispose();
5 context.Response.OutputStream.Write(ms.GetBuffer(), 0, (int)ms.Length);
6 ms.Close();
7 ms.Dispose();
而如果是其他进程的流操作文件时,之前操作文件的流却没释放所有资源的话,会抛出IOException。
2..NET中有些非托管对象有Close和Dispose,有些只有Dispose,网上有的说Close是Dispose的显式实现,会调用Dispose。不过我曾试过只调用Close然后用另一个进程的试图打开该文件,居然抛出IOException;但如果只调用Dispose就一切正常。然后网上又有说Close只是关闭连接,Dispose是释放相关的所有资源。于是实际操作中存在Close和Dispose的情况下,先调用Close然后再调用Dispose是最保险的做法。
3.之前一直以为非托管资源一定要程序员手动释放资源,但通过这次的机会上网看到资料说像FileStream对象实现了Finalize,里面就释放了非托管对象,当垃圾回收时就会自动释放资源,当然这样效率不高只是防止内存泄露的保底做法。而垃圾回收的发生时间为(1)内存不足的时候(这里还有哪一代区域的内存满了该如何操作的问题,详细请看
.Net垃圾回收机制
),(2)调用GC.Collect(),(3)程序域关闭就是AppDomain关闭(一个程序可以有多个程序域),(4)CLR关闭(就是程序关闭)。