Reputation: 1691
I am monitoring a folder for new files and need to process them. The problem is that occasionally file opening fails, because system has not finished copying it.
What is the correct way to test if the file is finished copying?
Clarification: I don't have write permissions to the folder/files and cannot control the copying process (it's the user).
Upvotes: 13
Views: 6845
Reputation: 1
Here's a vb.net loop I use. It waits 2 seconds between each check.
Dim donotcopy As Boolean = True
While donotcopy = True
Dim myFile As New FileInfo("Filetocopy")
Dim sizeInBytes As Long = myFile.Length
Thread.Sleep(2000)
Dim myFile2 As New FileInfo("Filetocopy")
Dim sizeInBytes2 As Long = myFile2.Length
If sizeInBytes2 = sizeInBytes Then donotcopy = False
End While
Upvotes: 0
Reputation: 7569
Are the files big?
Maybe you could try to calculate a the md5 checksum on the file?
If you put the md5 hash in the filename you could retrieve it and try to recalculate the checksum on the file. When the md5 is a match you could assume that the file is finished.
byte[] md5Hash = null;
MD5 md5 = new MD5CryptoServiceProvider();
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
md5Hash = md5.ComputeHash(fs);
StringBuilder hex = new StringBuilder();
foreach (byte b in md5Hash)
hex.Append(b.ToString("x2"));
Upvotes: 0
Reputation: 48066
In fact, to avoid race conditions, the only safe solution is to retry.
If you do something like:
while (file is locked)
no-op()
process file()
You risk another process jumping in between the while guard and the process file statement. No matter how your "wait for file availability" is implemented, unless you can ensure that post-unlock you're the first process to access it, you might not be that first user.
This is more likely that might seem at first glance, in particular if multiple people are watching the file, and in particular if they're using something like the file-system watcher. Course, it's still not particularly likely even then...
Upvotes: 0
Reputation: 171774
I think the only sure way to do this is by trying to open the file exclusively and catching a specific exception. I usually hate using exceptions for normal application logic, but I'm afraid for this scenario there's no other way (at least I haven't found one yet):
public bool FileIsDone(string path)
{
try
{
using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
{
}
}
catch(UnauthorizedAccessException)
{
return false;
}
return true;
}
Upvotes: 13
Reputation: 131112
It depends, a retry loop is probably the best you can do, if you have no control over the copy process.
If you do have control:
Upvotes: 0
Reputation: 1038810
If you are using FileSystemWatcher I don't think there's a robust solution to this problem. One approach would be try/catch/retry later.
Upvotes: 1
Reputation: 6360
Not sure about "the correct way", but you could use the monitoring tool (FileSystemWatcher
I guess) to fill an internal queue that you use for delayed processing. Or better yet: just use a queue to place files in that had the open fail, so you can retry them later.
Upvotes: 2
Reputation: 9509
You should also cover cases like: file is in use by other program, file was deleted (copy didn't succeed) etc..
Use an extended exception handling to cover all important cases that might occur.
Upvotes: 0
Reputation: 5141
one approach that i take always is to create a file in the end of my copy/transfer named "token.txt" without content. The idea is that this file will be created just in the end of the transfer operation, so you can monitor this file creation and when this file is created, you start to work with your files. Don't forget to erase this token file always when you start to process your files.
Upvotes: 0