0

I have 2 pieces of code. Take a look at this one.

static void Main(string[] args)
    {
        using (FileStream fs = new FileStream("temp.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            using (StreamWriter writer = new StreamWriter(fs))
            {
                writer.WriteLine("Hello World");
                using (StreamReader reader = new StreamReader(fs))
                {
                    Console.WriteLine(reader.ReadToEnd());
                } // Line-1
            } //Line-2 -> System.ObjectDisposedException: 'Cannot access a closed  file.'
        }
    }

At the Line-2 I get System.ObjectDisposedException occurs. Why do I get this exception here?

After a little bit of thinking I thought that the exception occurred at Line-2 because the Stream associated with reference 'fs' is already closed at Line-1. And at Line-2 it is trying to close the same stream again. And this answer made sense. Hence, I thought I had found the right answer to my question but then I tried something a little bit different.

Now look at this piece of code.

static void Main(string[] args)
    {
        using (FileStream fs = new FileStream("temp.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            using (StreamReader reader = new StreamReader(fs))
            {
                Console.WriteLine(reader.ReadToEnd());
                using (StreamWriter writer = new StreamWriter(fs))
                {
                    writer.WriteLine("Hello World");
                } // Line-1
            } // Line-2 -> No Exception occurred.
        }
    }

In this piece of code I didn't get any exception. Even though I am doing the same thing again. Here also the stream associated with reference 'fs' is already closed at Line-1 and it is also trying to close the stream at Line-2.

So why didn't I get any exception here?

My question is different from this Is there any way to close a StreamWriter without closing its BaseStream? because I am trying to do the same thing with the second code and despite the fact (in second code) that using statement already closed the base stream (fs) in Line-1. I still don't get any exception in Line-2.

Since @mjwills and @evk said the exception occurred because of flushing the contents of the stream after the file had been closed.

I tried this.

static void Main(string[] args)
    {
        using (FileStream fs = new FileStream("temp.txt", FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            using (StreamWriter writer = new StreamWriter(fs))
            {
                writer.WriteLine("Hello World");
                writer.Flush(); // Flushed the contents explicitly.
                using (StreamReader reader = new StreamReader(fs))
                {
                    Console.WriteLine(reader.ReadToEnd());
                } // Line-1
            } // Line-2 -> System.ObjectDisposedException: 'Cannot access a closed  file.' 
        }
    }

And the result is same I still have that exception even though I have explicitly flushed the contents. Please help.

gamerdev
  • 65
  • 6
  • 1
    Possible duplicate of [Is there any way to close a StreamWriter without closing its BaseStream?](https://stackoverflow.com/questions/2666888/is-there-any-way-to-close-a-streamwriter-without-closing-its-basestream) – mjwills Feb 11 '18 at 12:34
  • 1
    Problem is not in closing file multiple times. You can call Close\Dispose on FileStream multiple times with no issues. But you can't read\write to file after it has been closed, which includes flushing contents from buffer to disk - that's what happens in your first example (while in second example there is nothing to write\read on second close). – Evk Feb 11 '18 at 12:49
  • I am saying I have tried to flush the writer before entering the StreamReader's using block. – gamerdev Feb 11 '18 at 12:50
  • @Evk I called the the flush explicitly before even entering the StreamReader's using block. – gamerdev Feb 11 '18 at 12:51
  • 1
    Yes but difference is - `StreamWriter` will try to flush on close anyway. This try (even if there is nothing to flush really) is rejected when file is closed. `StreamReader` on the other hand does not try to flush anything (it's reader after all). – Evk Feb 11 '18 at 12:54
  • Thanks @Evk I got your point. – gamerdev Feb 11 '18 at 13:00
  • I think part of the issue here Learner is that you are looking at two 'wrong' ways of doing things, and asking 'why does Wrong Way A not work, when Wrong Way B did work'. I suggest you are thinking about the problem the wrong way around. Both Wrong Ways are ill advised - since you are interacting with an object that you **know** to be disposed. There are good (underlying) reasons why Wrong Way B did work, and Wrong Way A didn't (as per my and @Evk's comments) - but they are implementation details at best. _The right direction is to stop interacting with disposed objects._ – mjwills Feb 11 '18 at 20:44

1 Answers1

0

StreamWriter's Dispose method flushes to disk.

StreamReader's Dispose method does not (why would it? it is just a reader...).

As such, it is "kind of" safe to dispose the writer then the reader (in the sense that it works), but not vice versa.

Consider using leaveOpen on your StreamWriter and StreamReader to avoid this class of problem. By using leaveOpen, you are then able to manually Dispose the Stream which means you can be 100% confident the code will work - and not have to concern yourself with flushing behaviour etc etc.

mjwills
  • 23,389
  • 6
  • 40
  • 63