How to Remove FILE LOCKS? C#

11,046

Solution 1

Your code is correct, ignore the put-down about code smell. Disposing the PictureBox.Image is important to avoid out-of-memory exceptions.

This problem is caused by an implementation detail of the Bitmap class. When you open an image file, the class creates a memory-mapped file to map the pixel data of the image into memory. This was an important optimization for large images, it keeps the pixel data out of the paging file. It is not quite as important these days, 15 years after GDI+ was designed, modern machines have lots of RAM and disk space.

That memory-mapped file however creates a lock on the file. Important to prevent any other process with messing with the file data and invalidating the mapped view of the file. Which is what you are seeing, trying to replace or delete the file no longer works. You avoid it by creating a deep copy of the bitmap, a copy that has all of the pixel data in memory and no longer uses the file. Like this:

public static Bitmap LoadBitmapNolock(string path) {
    using (var img = Image.FromFile(path)) {
        return new Bitmap(img);
    }
}

Do note that the odds of running out of memory with large images on a 32-bit version of Windows is significantly increased with this code.

Solution 2

Manual use of .Dispose() in a managed language (like C#) is a Code Smell. You are probably ending up in some invalid state because you're trying to manually manage resources. Two ways that you may be able to avoid this are:

  1. Get rid of the unneeded .Dispose() elements (like opnDlg.Dispose()), and/or
  2. Try wrapping your objects that need disposing in a using(...){...} statement

either way, once you've refactored your code there shouldn't be any .Dispose() method calls in it. The objects that you are using either don't need to be manually managed, and trying to do so can only lead to problems, or they absolutely need to be managed, and therefore the using(...) statement is far superior because it guarantees releasing of the resource when exiting the code block.

Share:
11,046

Related videos on Youtube

John Ernest Guadalupe
Author by

John Ernest Guadalupe

I am an aspiring developer and currently am a student of Bachelor of Science in Computer Science at one of the Premier Technological Universities in the Philippines. I aim to be the best 3d MMORPG developer, and capable Systems developer with a focus on Android implementation. But as of yet, these are all dreams waiting to be fulfilled.

Updated on September 22, 2022

Comments

  • John Ernest Guadalupe
    John Ernest Guadalupe over 1 year

    So I am using C# and am making an enrollment system. So there is an option to add a picture and what I do, I prompt the user to pick a file and that file will then be Copied to the Directory folder and then renamed into the student's admission number. Here is the code for that browse button:

    OpenFileDialog openDlg = new OpenFileDialog();
                openDlg.Filter = "All JPEG files (*.jpg; *.jpeg)| *.jpg; *.jpeg";
                string filter = openDlg.Filter;
                openDlg.Multiselect = false;
                openDlg.Title = "Open a JPG File";
                if (openDlg.ShowDialog() == DialogResult.OK)
                {                
                    curFileName = openDlg.SafeFileName;
                    string curFilePath = openDlg.FileName;
    
                    openDlg.Dispose();
    
                    string sourcePath = @curFilePath.Remove((curFilePath.Length - curFileName.Length));
                    string targetPath = "@";
    
                    mycon.Open();
                    string cmdstr = "SELECT imageDirectory from userSettings WHERE ID = 1";
                    cmd = new OleDbCommand(cmdstr, mycon);
                    dr = cmd.ExecuteReader();
                    while (dr.Read())
                    {
                        targetPath = (@dr["imageDirectory"].ToString());
                    }
                    dr.Close();
                    mycon.Close();
    
                    string sourceFile = Path.Combine(sourcePath, curFileName);
                    string destFile = Path.Combine(targetPath, curFileName);
    
                    File.Copy(sourceFile, destFile, true);
    
                    newname = @destFile.Remove((destFile.Length - curFileName.Length)).ToString() + "\\" + (DateTime.Now.Year + "-" + textBox1.Text+".jpeg");
    
                    if (File.Exists(newname) == true)
                    {
                        pictureBox1.Image.Dispose();
                        try
                        {
                            File.Delete(newname);
                        }
    
                        catch (IOException ex)
                        {
                            MessageBox.Show(ex.ToString());
                            return;
                        }
                    }
    
                    File.Move(destFile, newname);
    
                    photoPath = newname;
                    pictureBox1.Image = Image.FromFile(photoPath);
    

    The problem are:

    a.) I have a function to allow the user to go to the next step and then if he wants to do some changes in the last step he could go back and update it. The problem here is when he changes the picture, I get an error stating "The file cannot be accessed because it is being used by another process"

    b.) When the user already uploaded a picture and then went back to the home page, he won't be able to upload a new picture when he decides to enroll again as well with an error stating: "The file cannot be accessed because it is being used by another process".

    The two errors both point here :

    `File.Delete(newname);`
    

    I really don't know what to do guys I have been looking for a solution to this since last night and I can't see a solution that wouldn't get me to change the whole code altogether. please help :(

  • John Ernest Guadalupe
    John Ernest Guadalupe over 11 years
    How do I use the using block? Sorry I am kind of new to file management in c#
  • Ichabod Clay
    Ichabod Clay over 11 years
    @JohnErnestGuadalupe You can read up over here: using Statement. Essentially, it works something like this... using (Foo bar = new Foo()) { //do stuff with bar }
  • John Ernest Guadalupe
    John Ernest Guadalupe over 11 years
    Thank very much for the insight ill use this and update you if there are any other problems thank you!
  • John Ernest Guadalupe
    John Ernest Guadalupe over 11 years
    okay so I just use this in my code before I call the File.Copy(), File.Exists() and File.Delete right?
  • user1703401
    user1703401 over 11 years
    No, replace your Image.FromFile() call at the bottom of your snippet with a call to this helper method.
  • John Ernest Guadalupe
    John Ernest Guadalupe over 11 years
    It worked like a charm!! thank you very much!! I didn't know something the error could be solved only by a short code! Thank you!!!
  • user1703401
    user1703401 almost 11 years
    @Idle - That crashes, unpredictably, with a "Generic error" when the image is drawn. Mind the MSDN Library warning: "You must keep the stream open for the lifetime of the Image".
  • Idle_Mind
    Idle_Mind almost 11 years
    Thanks for the info. I've never experienced that problem using FromStream. Can you give an example that easily creates this error?
  • user1703401
    user1703401 almost 11 years
    @Idle - lots of SO questions about it, here is one. But of course you'd only care about what the MSDN Library tells you to do, right?