Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finalization on StreamWriter and StreamReader

Tags:

c#

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?

like image 835
xdevel2000 Avatar asked Apr 28 '16 10:04

xdevel2000


2 Answers

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.

like image 134
James Thorpe Avatar answered Sep 20 '22 11:09

James Thorpe


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.

like image 39
Martin Liversage Avatar answered Sep 19 '22 11:09

Martin Liversage