Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will a using clause close this stream?

I've apparently worked myself into a bad coding habit. Here is an example of the code I've been writing:

using(StreamReader sr = new StreamReader(File.Open("somefile.txt", FileMode.Open))) {     //read file } File.Move("somefile.txt", "somefile.bak"); //can't move, get exception that I the file is open 

I thought that because the using clause explicitly called Close() and Dispose() on the StreamReader that the FileStream would be closed as well.

The only way I could fix the problem I was having was by changing the above block to this:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open)) {   using(StreamReader sr = new StreamReader(fs))   {     //read file   } }  File.Move("somefile.txt", "somefile.bak"); // can move file with no errors 

Should closing the StreamReader by disposing in the first block also close the underlying FileStream? Or, was I mistaken?

Edit

I decided to post the actual offending block of code, to see if we can get to the bottom of this. I am just curious now.

I thought I had a problem in the using clause, so I expanded everything out, and it still can't copy, every time. I create the file in this method call, so I don't think anything else has a handle open on the file. I've also verified that the strings returned from the Path.Combine calls are correct.

private static void GenerateFiles(List<Credit> credits) {     Account i;     string creditFile = Path.Combine(Settings.CreditLocalPath, DateTime.Now.ToString("MMddyy-hhmmss") + ".credits");      StreamWriter creditsFile = new StreamWriter(File.Open(creditFile, FileMode.Create));      creditsFile.WriteLine("code\inc");      foreach (Credit c in credits)     {         if (DataAccessLayer.AccountExists(i))         {             string tpsAuth = DataAccessLayer.GetAuthCode(i.Pin);             creditsFile.WriteLine(String.Format("{0}{1}\t{2:0.00}", i.AuthCode, i.Pin, c.CreditAmount));         }         else         {             c.Error = true;             c.ErrorMessage = "NO ACCOUNT";         }          DataAccessLayer.AddCredit(c);      }      creditsFile.Close();     creditsFile.Dispose();      string dest =  Path.Combine(Settings.CreditArchivePath, Path.GetFileName(creditFile));     File.Move(creditFile,dest);     //File.Delete(errorFile); } 
like image 963
scottm Avatar asked Apr 01 '09 21:04

scottm


People also ask

Does using statement close stream?

using ensures that Dispose() will be called, which in turn calls the Close() method. You can assume that all kinds of Streams are getting closed by the using statement.

Does closing a StreamReader close the underlying stream?

Yes, StreamReader , StreamWriter , BinaryReader and BinaryWriter all close/dispose their underlying streams when you call Dispose on them.

Does StreamWriter dispose stream?

It does not dispose the stream. It simply closes it.

What is MemoryStream in C# with example?

The MemoryStream class creates streams that have memory as a backing store instead of a disk or a network connection. MemoryStream encapsulates data stored as an unsigned byte array that is initialized upon creation of a MemoryStream object, or the array can be created as empty.


2 Answers

Yes, StreamReader.Dispose closes the underlying stream (for all public ways of creating one). However, there's a nicer alternative:

using (TextReader reader = File.OpenText("file.txt")) { } 

This has the added benefit that it opens the underlying stream with a hint to Windows that you'll be accessing it sequentially.

Here's a test app which shows the first version working for me. I'm not trying to say that's proof of anything in particular - but I'd love to know how well it works for you.

using System; using System.IO;  class Program {     public static void Main(string[] args)     {         for (int i=0; i < 1000; i++)         {             using(StreamReader sr = new StreamReader                   (File.Open("somefile.txt", FileMode.Open)))             {                 Console.WriteLine(sr.ReadLine());             }             File.Move("somefile.txt", "somefile.bak");             File.Move("somefile.bak", "somefile.txt");         }     } } 

If that works, it suggests that it's something to do with what you do while reading...

And now here's a shortened version of your edited question code - which again works fine for me, even on a network share. Note that I've changed FileMode.Create to FileMode.CreateNew - as otherwise there could still have been an app with a handle on the old file, potentially. Does this work for you?

using System; using System.IO;  public class Test {         static void Main()     {         StreamWriter creditsFile = new StreamWriter(File.Open("test.txt",                                            FileMode.CreateNew));          creditsFile.WriteLine("code\\inc");          creditsFile.Close();         creditsFile.Dispose();          File.Move("test.txt", "test2.txt");     } } 
like image 99
Jon Skeet Avatar answered Oct 04 '22 07:10

Jon Skeet


Note - your using blocks do not need to be nested in their own blocks - they can be sequential, as in:

using(FileStream fs = File.Open("somefile.txt", FileMode.Open)) using(StreamReader sr = new StreamReader(fs)) {     //read file } 

The order of disposal in this case is still the same as the nested blocks (ie, the StreamReader will still dispose before the FileStream in this case).

like image 37
Not Sure Avatar answered Oct 04 '22 08:10

Not Sure