Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileStream "cannot access closed file"

Tags:

c#

filestream

Why am I receiving the above error message when I use using (fileStream = new FileStream(path, FileMode.Append, FileAccess.Write)) but the programme executes perfectly when I replace it with fileStream = File.Create(path); ?

I want to append the console output to an external file. Here's my code:

 //copy console output to file in bin\Debug folder
    class ConsoleCopy : IDisposable
    {
        FileStream fileStream;
        StreamWriter fileWriter;
        TextWriter doubleWriter;
        TextWriter oldOut;
        class DoubleWriter : TextWriter
        {
            TextWriter one;
            TextWriter two;
            public DoubleWriter(TextWriter one, TextWriter two)
            {
                this.one = one;
                this.two = two;
            }
            public override Encoding Encoding
            {
                get { return one.Encoding; }
            }
            //Clears all buffers for the current writer
            public override void Flush()
            {
                one.Flush();

                two.Flush();
            }
            public override void Write(char value)
            {
                **one.Write(value);**//error thrown here
                two.Write(value);
            }
        }
        public ConsoleCopy(string path)
        {
            oldOut = Console.Out;
            try
            {
                **//fileStream = File.Create(path);** //runs alright with this line
                fileWriter = new StreamWriter(fileStream);
                fileWriter.AutoFlush = true;
                doubleWriter = new DoubleWriter(fileWriter, oldOut);
            }
            catch (Exception e)
            {
                Console.WriteLine("Cannot open file for writing");
                Console.WriteLine(e.Message);
                return;
            }
            Console.SetOut(doubleWriter);
        }
        public void Dispose()
        {
            Console.SetOut(oldOut);
            if (fileWriter != null)
            {
                fileWriter.Flush();
                fileWriter.Close();
                fileWriter = null;
            }
            if (fileStream != null)
            {
                fileStream.Close();
                fileStream = null;
            }
        }
    }//end of consoleCopy

I call this method in my main method as such:

 //pass output to ConsoleCopy method for copying to .txt file
        using (var cc = new ConsoleCopy("mylogfile.txt"))
        {
           DateTime theDate = DateTime.UtcNow;

            string custom = theDate.ToString("d");

            Console.WriteLine("User has logged in on " + custom);
        }

UPDATE:

The error was previously shown at one.Write(value). I've managed to solve it though thanks to Peter. Thanks everyone for your contributions and help :)

like image 643
iNeedHelp Avatar asked Apr 14 '15 00:04

iNeedHelp


2 Answers

Edit: If you're getting it before you write, then it's because I misread the question and putting the using statement in the ConsoleCopy constructor means that when the ConsoleCopy is finished being created, the FileStream is closed then. By the time you try to write to it, because it's already been closed you get that exception. The same solution would apply - leave the FileStream open and close it in Dispose() where it should be with the using statement in the main method.

If I understand correctly, you get that exception on disposal, right? If so, that's because what's happening is essentially that you're closing that stream twice.

using (var cc = new ConsoleCopy("mylogfile.txt"))
{
    // At this time, your filestream is created with the using statement.
    // Writing happens here.
    // Your filestream is closed at the end of the using statement inside of the ConsoleCopy constructor.
} 
// At this point, ConsoleCopy tries to call Dispose(), which flushes and closes everything again. However, this throws an exception because the using statement already closed the FileStream.

If your goal is to append to the end of the file and your Dispose() method closes everything internally, why not just replace

**//fileStream = File.Create(path);** //runs alright with this line

with

fileStream = File.Open(path, System.IO.FileMode.Append, System.IO.FileAccess.Write);

and let the using statement in your main close the streams internally for you?

like image 86
Peter Luu Avatar answered Sep 21 '22 07:09

Peter Luu


Are you running the write code outside of the using statement? You might be closing the stream before doing anything with it.

What happens when you run this:

using (fileStream = new FileStream(path, FileMode.Append, FileAccess.Write))
{
  fileWriter = new StreamWriter(fileStream);
  fileWriter.AutoFlush = true;
  doubleWriter = new DoubleWriter(fileWriter, oldOut);
}
like image 37
Colin Avatar answered Sep 25 '22 07:09

Colin