xdevel2000
xdevel2000

Reputation: 21364

Finalization on StreamWriter and StreamReader

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?

Upvotes: 6

Views: 750

Answers (4)

Martin Liversage
Martin Liversage

Reputation: 106796

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.

Upvotes: 3

James Thorpe
James Thorpe

Reputation: 32192

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.

Upvotes: 5

Qwertiy
Qwertiy

Reputation: 21380

Operation sytem frees handles and memory owned by application, if the were not freed by application if it closes. Anyway, I'm sure Stream has finalizer.

Upvotes: 0

NineBerry
NineBerry

Reputation: 28499

The operating system has a list which process (application) has what file opened. If your process terminates without explicitly closing the file, the operating system still knows that it is not any longer accessing the file and so can allow other requests to access the file.

Upvotes: 0

Related Questions