How do I tell my C# application to close a file it has open in a FileInfo object or possibly Bitmap object?

Evan C picture Evan C · Jan 17, 2011 · Viewed 10.5k times · Source

So I was writing a quick application to sort my wallpapers neatly into folders according to aspect ratio. Everything is going smoothly until I try to actually move the files (using FileInfo.MoveTo()). The application throws an exception:

System.IO.IOException The process cannot access the file because it is being used by another process.

The only problem is, there is no other process running on my computer that has that particular file open. I thought perhaps that because of the way I was using the file, perhaps some internal system subroutine on a different thread or something has the file open when I try to move it. Sure enough, a few lines above that, I set a property that calls an event that opens the file for reading. I'm assuming at least some of that happens asynchronously. Is there anyway to make it run synchronously? I must change that property or rewrite much of the code.

Here are some relevant bits of code, please forgive the crappy Visual C# default names for things, this isn't really a release quality piece of software yet:

private void button1_Click(object sender, EventArgs e)
{
    for (uint i = 0; i < filebox.Items.Count; i++)
    {
        if (!filebox.GetItemChecked((int)i)) continue;

        //This calls the selectedIndexChanged event to change the 'selectedImg' variable
        filebox.SelectedIndex = (int)i;

        if (selectedImg == null) continue;

        Size imgAspect = getImgAspect(selectedImg);

        //This is gonna be hella hardcoded for now
        //In the future this should be changed to be generic
        //and use some kind of setting schema to determine
        //the sort/filter results

        FileInfo file = ((FileInfo)filebox.SelectedItem);

        if (imgAspect.Width == 8 && imgAspect.Height == 5)
        {
            finalOut = outPath + "\\8x5\\" + file.Name;
        }
        else if (imgAspect.Width == 5 && imgAspect.Height == 4)
        {
            finalOut = outPath + "\\5x4\\" + file.Name;
        }
        else
        {
            finalOut = outPath + "\\Other\\" + file.Name;
        }

        //Me trying to tell C# to close the file
        selectedImg.Dispose();
        previewer.Image = null;

        //This is where the exception is thrown
        file.MoveTo(finalOut);
    }
}

//The suspected event handler
private void filebox_SelectedIndexChanged(object sender, EventArgs e)
{
    FileInfo selected;
    if (filebox.SelectedIndex >= filebox.Items.Count || filebox.SelectedIndex < 0) return;
    selected = (FileInfo)filebox.Items[filebox.SelectedIndex];

    try
    {
        //The suspected line of code
        selectedImg = new Bitmap((Stream)selected.OpenRead());
    }
    catch (Exception) { selectedImg = null;  }

    if (selectedImg != null)
        previewer.Image = ResizeImage(selectedImg, previewer.Size);
    else
        previewer.Image = null;
}

I have a long-fix in mind (that's probably more efficient anyway) but it presents more problems still :/

Any help would be greatly appreciated.

Answer

Mark Hall picture Mark Hall · Dec 25, 2013

Since you are using your selectedImg as a Class scoped variable it is keeping a lock on the File while the Bitmap is open. I would use an using statement and then Clone the Bitmap into the variable you are using this will release the lock that Bitmap is keeping on the file.

Something like this.

using ( Bitmap img  = new Bitmap((Stream)selected.OpenRead()))
{
    selectedImg = (Bitmap)img.Clone();
}