Question

I have a form application that performs a simulation and constantly reads/writes a binary file. Everything works fine if you let it run through. However, if the form is closed/ the simulation is aborted the file-stream is not closed properly - leaving the file locked. Is there a way to make sure all streams closed? I tried the following - but it has no effect... Thanks a lot in advance, T

        public BinaryWriter BinWrite;
        public BinaryReader BinRead;

        public BinaryWriter EnvBinWrite;
        public BinaryReader EnvBinRead;       

public void theForm_FormClosing(object sender, FormClosingEventArgs e)
        {

            //Close all binary file reader/writers -- crashes if it cannot overwrite files
            foreach (Building B in AllBldgs)
            {
                try
                {
                    EnvBinRead.Close();
                }
                catch
                { continue; }
                try
                {
                    EnvBinWrite.Close();
                }
                catch
                { continue; }
                try
                {
                    BinRead.Close();
                }
                catch
                { continue; }

                try
                {
                    BinWrite.Close();
                }
                catch
                { continue; }
            }
        }
Was it helpful?

Solution

Are you sure you know what the continue keyword is for? Please note that this continues with the next loop, not the next block of code. So if an exception occurs closing EnvBinRead, you will not enter the block to close EnvBinWrite, but continue with the next item from AllBldgs.

To eat all exceptions and still try to close all the binary writers, you'd write:

foreach (Building B in AllBldgs)
{
    try
    {
        EnvBinRead.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing EnvBinRead failed!" + exp.ToString());
    }

    try
    {
        EnvBinWrite.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing EnvBinWrite failed!" + exp.ToString());
    }

    try
    {
        BinRead.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing BinRead failed!" + exp.ToString());
    }

    try
    {
        BinWrite.Close();
    }
    catch (Exception exp)
    { 
        Console.WriteLine("Closing BinWrite failed!" + exp.ToString());
    }
}

Please note that simply eating the exceptions is never a good idea. If you don't care whether the reader or write could be closed, check whether it has been initialized before closing it as suggested in the comments.

OTHER TIPS

You should call dispose to close the BinaryReader and Writer.

Explanation:

StreamReader, StreamWriter, BinaryReader and BinaryWriter all close/dispose their underlying streams when you call Dispose on them. They don't dispose of the stream if the reader/writer is just garbage collected though - you should always dispose of the reader/writer, preferrably with a using statement. (In fact, none of these classes have finalizers, nor should they have.)

Personally I prefer to have a using statement for the stream as well. You can nest using statements without braces quite neatly:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

Even though the using statement for the stream is somewhat redundant (unless the StreamReader constructor throws an exception) I consider it best practice as then if you get rid of the StreamReader and just use the stream directly at a later date, you'll already have the right disposal semantics.

It is always good to use Using block for the streams, Closing them immediately after use.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top