Robert
Robert

Reputation: 1845

File.Copy FileNotFoundException reported randomly when it's never true

The code is very simple.

If File.Exists(strFileMovingTo) Then File.Delete(strFileMovingTo)
If File.Exists(strFileMovingTo) Then
    Call SendEmail(Globals.EmailInternetTeam, "[email protected]", "Display Jpg Problem", "The file " & strFileMovingTo & " cannot be removed by the file mover(to allow a new file to be moved over)")
    Return False
Else
    If File.Exists(strFileMovingFrom) Then
        File.Copy(strFileMovingFrom, strFileMovingTo, True)
        If File.Exists(strFileMovingTo) = False Then
            ''tried to copy file over but must have failed ... send email
            Call SendEmail(Globals.EmailInternetTeam, "[email protected]", "Display Jpg Problem", "The file cannot be moved by the file mover from " & strFileMovingFrom & " to " & strFileMovingTo & ". Please have a look at why.")
            Return False
        Else
            Return True
        End If
    End If
    Return False
    ''make sure this file exists on fad dev
End If

However a FileNotFoundException exception is thrown during File.Copy even though its wrapped in a If File.Exists ... End If to check its existance.

The great thing is if you run this through the debugger it nearly always works, when released as an app it almost never works.

Scarily the file always exists.

Anyone know what's going on?

Upvotes: 1

Views: 789

Answers (5)

user215054
user215054

Reputation:

When working with some of file functions of Windows API, which also should be true for .NET one should always be aware about asynchronous nature of file system functions. Asynchronous, means that there is a non-zero, unpredictable, non-guaranteed time between you call to API affecting file system and next successful call to the same API related to the file or directory.

In non-transactional APIs it is common mistake to call something like "create file" then immediatelly try to "findFirst" and fail. Just treat the file system as messaging system with unpredictable delays and develop sort of "protocol" with repetitive polling, sleeps and timeouts or event notifications and callbacks.

However since introduction of Vista there is a different set of guarantees and expectations when applications can use so named "transactional" file API.

Upvotes: 0

Dave Swersky
Dave Swersky

Reputation: 34810

The fact that it works in debug tells me it's a timing problem. You're not waiting long enough for the deletes or other file system changes to happen.

Build in a wait of one to two seconds after making file system changes.

UPDATE:

How about this: Create a shared dictionary of file moves you want to perform and use a FileSystemWatcher to carry out the copy action.

If File.Exists(strFileMovingTo) Then File.Delete(strFileMovingTo)
        Thread.Sleep(1000) --Add wait
        If File.Exists(strFileMovingTo) Then
            Call SendEmail(Globals.EmailInternetTeam, "[email protected]", "Display Jpg Problem", "The file " & strFileMovingTo & " cannot be removed by the file mover(to allow a new file to be moved over)")
            Return False
        Else
            If File.Exists(strFileMovingFrom) Then
                File.Copy(strFileMovingFrom, strFileMovingTo, True)
                Thread.Sleep(1000) --Add wait
                If File.Exists(strFileMovingTo) = False Then
                    'tried to copy file over but must have failed ... send email
                    Call SendEmail(Globals.EmailInternetTeam, "[email protected]", "Display Jpg Problem", "The file cannot be moved by the file mover from " & strFileMovingFrom & " to " & strFileMovingTo & ". Please have a look at why.")
                    Return False
                Else
                    Return True
                End If
            End If
            Return False
            'make sure this file exists on fad dev
        End If

Upvotes: 0

Guillaume
Guillaume

Reputation: 13138

There is many race condition, you shouldn't blindly rely on File.Exists for other file operations. Anybody can delete or add a file with the same name between two function calls.

If File.Exists(strFileMovingFrom) Then
    // AT THIS TIME, another thread or another process might run
    // the equivalent to **File.Delete(strFileMovingFrom)**
    File.Copy(strFileMovingFrom, strFileMovingTo, True) //Can throw!

Upvotes: 0

Kev
Kev

Reputation: 119806

I agree with Dave's answer that this looks like a timing issue. Also, if a file can't be deleted for any reason then usually File.Delete will throw an exception. Perhaps you should be catching that instead and reworking your logic.

Upvotes: 0

Gonzalo
Gonzalo

Reputation: 21175

There's probably something else deleting the file and there's a race condition between the call to File.Exists and File.Copy.

Upvotes: 1

Related Questions