If I have this:
StreamWriter cout = new StreamWriter("test.txt");
cout.WriteLine("XXX");
// here IOException...
StreamReader cin = new StreamReader("test.txt");
string text = cin.ReadLine();
the clr throws an IOException
because I haven't close the cout
.
In fact If I do this:
StreamWriter cout = new StreamWriter("test.txt");
cout.WriteLine("XXX");
cout.Close();
StreamReader cin = new StreamReader("test.txt");
string text = cin.ReadLine();
I have no exception.
But If I do this and then exit from the application:
StreamReader cin = new StreamReader("test.txt");
string text = cin.ReadLine();
without closing cin
the file can from the OS opened and written.
However reading the source code of StreamReader.cs
I didn't' find a destructor method (i.e. ~StreamReader(...)
). So who does free that file if the garbage collector doesn't invoke Dispose
and there is no finalization method?
Internally, the StreamReader
uses a FileStream
:
Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, DefaultFileStreamBufferSize, FileOptions.SequentialScan, Path.GetFileName(path), false, false, checkHost);
The FileStream
class, being the class that ultimately accesses the file and therefore needs to guarantee cleanup, does have a finalizer, which closes the actual underlying stream. The Dispose
method on the StreamReader
just calls the Close
on the underlying FileStream
.
StreamReader
and StreamWriter
uses a FileStream
to access the file. FileStream
uses SafeFileHandle
to store the underlying OS file handle. As the SafeFileHandle
class controls an unmanaged resource it correctly has a finalizer (what you call a destructor) that closes the file handle.
But If I do this and then exit from the application: [...] without closing cin the file can from the OS opened and written
When a process terminates all resources used by that process is released to the operating system. It doesn't matter if your application forgot to close a file handle (even though SafeFileHandle
will not "forget"). You will always observe the described behavior no matter how badly written your application is.
I just want to point out that the best way to work with StreamReader
and StreamWriter
and similar classes is using
:
using (StreamWriter cout = new StreamWriter("test.txt")) {
cout.WriteLine("XXX");
}
using (StreamReader cin = new StreamReader("test.txt")) {
string text = cin.ReadLine();
}
This deterministically closes the files when the using
block ends even if an exception is thrown while processing the file.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With