tags:

views:

79

answers:

5

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?

A: 

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
Dave Swersky
I did consider this, but this app only runs once a minute and quite often the files have been there for a few seconds, onces that fail have sometimes sat there for 2 or 3 minutes before being transferred.I wonder if File.Exists actually 'locks' the file briefly
Robert
I think it's the Delete that is causing your problem. The code runs so fast it tries to copy the file before the Delete command has had time to finish.
Dave Swersky
I'll add in the sleeps but the file.delete is rarely if ever called since the files are only ever uploaded once. usually... i'll add in the sleeps :)
Robert
Waiting a second is almost never the answer, if we do need to wait what ever time you pick willnot be correct every time. If this code ever helps it will still sometimes fail, either under heavy load or when asked to move a bigger then normal file, or when the disk is more fragmented.
David Waters
The wait isn't the issue... Is it because I am using UNC paths and the source is a network path and the destination is a network path?
Robert
@David: That's true... if the sleeps help that only serves to confirm that the problem is a race condition. @Robert: If the sleeps help, then use a while loop or something like that to ensure that the wait lasts long enough to ensure the file deletion has completed.
Dave Swersky
@Robert: The fact that you are going over the network strengthens the case for a race condition.
Dave Swersky
+1  A: 

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

Gonzalo
This application deletes the file itself from the source if the above method returns true
Robert
Then why don't just do a File.Move?
Gonzalo
@Gonzalo- I don't think a File.Move would help. The problem is that the File operations are non-blocking, so they can't be guaranteed to have completed by the time the rest of the routine completes.
Dave Swersky
A: 

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.

Kev
A: 

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!
Guillaume
I realise but please presume this is not the case, although it can happen it is not the cause of this common problem. The file throwing the not found exception can actually be moved 20 minutes later by the process. Is it perhaps the source and destination are unc paths on different servers?
Robert
I advice you to think about a more robust solution for network files. See how ROBOCOPY works...You may build a helper that retry many times.
Guillaume
A: 

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.

RocketSurgeon