Solved

'Process cannot access the file' IOException upon attempted file deletion

Posted on 2004-04-27
11
284 Views
Last Modified: 2012-08-13
Hello,

Extremely irritatingly, I'm having problems trying to delete a file that has previously had work done upon it through GDI+. I make sure that any references to the file are correctly disposed of, but I still receive a "The process cannot access the file because it is being used by another process" error when attempting its deletion.

A summary of the code is below:

        Dim fullPath As String = "..." ' path to input file

        If File.Exists(Server.MapPath(fullPath)) Then
            Dim inputImage As Image = Image.FromFile(Server.MapPath(fullPath))
            Dim originalWidth As Integer = inputImage.Width
            Dim originalHeight As Integer = inputImage.Height
            Dim originalFormat As Imaging.ImageFormat = inputImage.RawFormat
            Dim tempBitmap As Bitmap

            ' crop left-hand side of image
            If Request.QueryString("cropleft") <> "" Then
                If Request.QueryString("cropleft") > 0 Then
                    Dim cropLeft As Integer = Request.QueryString("cropleft")

                    ' define new width of preview
                    originalWidth = originalWidth - cropLeft

                    ' define new image size
                    tempBitmap = New Bitmap(inputImage.Width - cropLeft, inputImage.Height)
                    Dim g As Graphics = Graphics.FromImage(tempBitmap)

                    ' overloaded definition #27:
                    g.DrawImage(inputImage, New Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), cropLeft, 0, tempBitmap.Width, tempBitmap.Height, GraphicsUnit.Pixel)
                    g.Dispose()

                    ' reassign input image
                    inputImage = tempBitmap
                End If
            End If

            ' this cropping is repeated for the other dimensions
            ' here...

            ' define the output in the given dimensions
            Dim outputImage As New Bitmap(inputImage, originalWidth, originalHeight)
 
            ' rotate the image if requested
            If Request.QueryString("rotate") <> "" Then
                Dim flipType As RotateFlipType
                Select Case Request.QueryString("rotate")
                    Case "left"
                        flipType = RotateFlipType.Rotate270FlipNone
                    Case "right"
                        flipType = RotateFlipType.Rotate90FlipNone
                End Select

                If flipType > 0 Then
                    outputImage.RotateFlip(flipType)
                End If
            End If

            ' save back to temp file
            Dim newPath As String = "..." ' original path again
            outputImage.Save(newPath & ".temp", originalFormat)

            ' tidy up  
            tempBitmap.Dispose()
            inputImage.Dispose()
            outputImage.Dispose()

            ' wait a bit because file is not released rightaway
            Dim thenTicks As Long = Now.AddSeconds(10).Ticks  ' I have even put this wait up to 30+ seconds but it makes no difference...
                                                              ' Surely I don't need a looping try/catch until this passes?
            While Now.Ticks < thenTicks
                Dim spin As String = "spinning"
            End While

            ' overwrite old file with the new
            Dim fi As New FileInfo(newPath)
            fi.MoveTo(newPath & ".old") ' this fails with the Exception mentioned above
            ' fi.Delete fails, as well as CopyTo below, with the 'overwrite file' boolean as True


            ' don't even get as far as below due to exception, so update file
            fi = New FileInfo(newPath & ".temp")
            fi.CopyTo(newPath)
            fi.Delete()

       End If

Can anyone see any obvious problems with this? I had similar problems in a separate part of the Application at an earlier date, but the wait of ten seconds for files to be released did the job. However, GDI+ was not being used in the latter situation, just IO.

Thanks in advance,

Wolfy
0
Comment
Question by:WolfyUK
  • 6
  • 3
  • 2
11 Comments
 
LVL 37

Assisted Solution

by:gregoryyoung
gregoryyoung earned 153 total points
ID: 10932266
inputimage is coming from Image.FromFile()

image.FromFile will retain a lock until it is disposed ...

inputImage = tempBitmap is being reassigned and as such not disposed.
0
 
LVL 2

Expert Comment

by:Jeffr0
ID: 10932386
Hi.  I just took your code and altered it to work on my machine-- just changed the file paths and added a couple of variables.

When I run it, it does the modifications to Picture.bmp... saves it as NewVersion.bmp... and then renames the new file to NewVersion.bmp.old.  This works with no errors with or without the timer.


        Dim fullPath As String = "C:\Picture.bmp"

        If File.Exists(fullPath) Then
            Dim inputImage As Image = Image.FromFile(fullPath)
            Dim originalWidth As Integer = inputImage.Width
            Dim originalHeight As Integer = inputImage.Height
            Dim originalFormat As Imaging.ImageFormat = inputImage.RawFormat
            Dim tempBitmap As Bitmap

            Dim CropLeft As Integer = 25
            Dim Rotate As String = "left"

            ' crop left-hand side of image

            If CropLeft > 0 Then
                ' define new width of preview
                originalWidth = originalWidth - CropLeft

                ' define new image size
                tempBitmap = New Bitmap(inputImage.Width - CropLeft, inputImage.Height)
                Dim g As Graphics = Graphics.FromImage(tempBitmap)

                ' overloaded definition #27:
                g.DrawImage(inputImage, New Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), CropLeft, 0, tempBitmap.Width, tempBitmap.Height, GraphicsUnit.Pixel)
                g.Dispose()

                ' reassign input image
                inputImage = tempBitmap
            End If


            ' this cropping is repeated for the other dimensions
            ' here...

            ' define the output in the given dimensions
            Dim outputImage As New Bitmap(inputImage, originalWidth, originalHeight)

            ' rotate the image if requested
            If Rotate <> "" Then
                Dim flipType As RotateFlipType
                Select Case Rotate
                    Case "left"
                        flipType = RotateFlipType.Rotate270FlipNone
                    Case "right"
                        flipType = RotateFlipType.Rotate90FlipNone
                End Select

                If flipType > 0 Then
                    outputImage.RotateFlip(flipType)
                End If
            End If

            ' save back to temp file
            Dim newPath As String = "C:\NewVersion.bmp" ' original path again
            outputImage.Save(newPath, originalFormat)

            ' tidy up  
            tempBitmap.Dispose()
            inputImage.Dispose()
            outputImage.Dispose()

            '' wait a bit because file is not released rightaway
            'Dim thenTicks As Long = Now.AddSeconds(10).Ticks  ' I have even put this wait up to 30+ seconds but it makes no difference...
            '' Surely I don't need a looping try/catch until this passes?
            'While Now.Ticks < thenTicks
            '    Dim spin As String = "spinning"
            'End While

            ' overwrite old file with the new
            Dim fi As New FileInfo(newPath)
            fi.MoveTo(newPath & ".old") ' this fails with the Exception mentioned above
0
 
LVL 2

Accepted Solution

by:
Jeffr0 earned 180 total points
ID: 10932741
It may be that the Garbage Collection is not running right away on your box.

In the code after the .Dispose() calls, add this line.

GC.Collect()

That may ensure that the objects are actually disposed during your "spinning" loop.
0
Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

 
LVL 37

Expert Comment

by:gregoryyoung
ID: 10932762
or just actually dispose the reference you are sending out to never never land before you do such ...

0
 
LVL 2

Author Comment

by:WolfyUK
ID: 10933296
Thanks for your suggestions. I will let you know how I get on when I'm back in work next week.

Thanks,

Wolfy
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11002229
How did this work out ?
0
 
LVL 2

Author Comment

by:WolfyUK
ID: 11003832
Only just got back into work!

The problem definitely lied within the disposal of objects. The only way I could fix it was by disposing of each inputImage within the 'cropping' sections before reassigning it as the tempBitmap, as well as keeping the spin delay and GC.Collect().

Thanks for your help, I'll split the points.

Wolfy
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11003884
nooooooooooooooooooooooo


I just did this here ......

GC.Collect is evil here ...

you are losing your reference (thus not disposing it)

                ' overloaded definition #27:
                g.DrawImage(inputImage, New Rectangle(0, 0, tempBitmap.Width, tempBitmap.Height), CropLeft, 0, tempBitmap.Width, tempBitmap.Height, GraphicsUnit.Pixel)
                g.Dispose()

***********************************
                inputImage = tempBitmap
***********************************
            End If


            ' this cropping is repeated for the other dimensions
            ' here...

            ' define the output in the given dimensions
            Dim outputImage As New Bitmap(inputImage, originalWidth, originalHeight)


try disposing it before you toss the reference.
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11003891
in above code you called inputimage = image.fromfile() which locks the file till disposed ... here you are throwing away the reference and forcing the garbage collector to dispose it.
0
 
LVL 2

Author Comment

by:WolfyUK
ID: 11012769
Sorry if I wasn't clear enough, but I did add inputImage.Dispose()s before each inputImage = tempBitmap, but this would only work alongside the GC.Collect() and spin delay.
0
 
LVL 37

Expert Comment

by:gregoryyoung
ID: 11015903
btw: you also dispose the same image twice here
             tempBitmap.Dispose()
            inputImage.Dispose()
0

Featured Post

DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question