Checking File sizes for changes
I have an app that watches a folder for incoming jobs and then processes them. A job consists of a Folder with several job files inside the folder. Jobs are usually copied over the internet so when a folder is added to my Watched Folder I'm having my app get the attributes for the files inside the job folder, wait 20 seconds, and compare the current attributes for NSFileSize to see if there have been any changes. When everything matches, and no changes are detected it can pass the job folder along to be processed. This is the code I have:
while (fileSizes == NO && fileCount == NO) {
NSLog(@"going for a loop");
NSArray *jobFiles = [fm subpathsAtPath:jobPath];
NSMutableArray *jobFileAttrs = [[NSMutableArray alloc] init];
int i = 0;
while (i < [jobFiles count]) {
NSString *filePath = [jobPath stringByAppendingPathComponent:[jobFiles objectAtIndex:i]];
[jobFileAttrs addObject:[fm attributesOfItemAtPath:filePath error:nil]];
++i;
}
sleep(20);
NSArray *jobFiles2 = [fm subpathsAtPath:jobPath];
NSMutableArray *jobFileAttrs2 = [[NSMutableArray alloc] init];
i = 0;
while (i < [jobFiles2 count]) {
NSString *filePath = [jobPath stringByAppendingPathComponent:[jobFiles2 objectAtIndex:i]];
[jobFileAttrs2 addObject:[fm attributesOfItemAtPath:filePath error:nil]];
++i; 开发者_如何学C
}
if ([jobFiles count] == [jobFiles2 count]) {
i = 0;
fileSizes = YES;
while (i < [jobFiles count]) {
NSLog(@"Does %ul = %ul", [[jobFileAttrs objectAtIndex:i] objectForKey:NSFileSize], [[jobFileAttrs2 objectAtIndex:i] objectForKey:NSFileSize]);
if ([[jobFileAttrs objectAtIndex:i] objectForKey:NSFileSize] != [[jobFileAttrs2 objectAtIndex:i] objectForKey:NSFileSize]){
fileSizes = NO;
}
++i;
}
if (fileSizes)
fileCount = YES;
}
This code works as intended in Lion, but when I run the App on Snow Leopard I get inconsistent values for the NSFileSize attribute. Every time the loop runs I get a completely different set of value than even the previous loop. This is obviously for a folder full of files that is no longer being copied and should give matching values for the file sizes.
Why doesn't this work in Snow Leopard, and what do I need to do to fix this? Part of my problem is I'm only set up for development on a Lion Machine, so I have to make build, and then transfer it to a snow leopard machine with out a debugger to test. It's making it hard for me to trouble shoot.
There are a few problems with this but for one thing, you are comparing the value of two objects using a boolean operator (!=
). This is comparing the pointer locations of the two objects, not their value.
To compare two objects, you must use the isEqual:
method:
if (![[[jobFileAttrs objectAtIndex:i] objectForKey:NSFileSize] isEqual:[[jobFileAttrs2 objectAtIndex:i] objectForKey:NSFileSize]])
{
fileSizes = NO;
}
Secondly, this is fundamentally bad design. What your code is doing is called polling, and the presence of sleep()
in the code is a bad sign. You should never use sleep
in Cocoa code, especially if your code is executing on the main thread as it will block the main run loop.
If you absolutely must use polling, you should use an NSTimer
object.
However, in this particular case you don't need to use polling to determine when there has been a change to the folder contents, you can use the FSEvents
API instead. The API is C-based and a bit obtuse so you might want to use Stu Connolly's SCEvents
Objective-C wrapper.
What you should be doing is maintaining an array of the current files and their file sizes (probably as an NSArray
instance variable containing dictionaries with keys for file name and file attributes) and then when you are notified of a change on disk, get the current status of the files and compare that with the information in your stored array. You would then replace your stored array with the updated file information.
The other file monitoring option is kqueues
. These differ from FSEvents
in that they are specific to a particular file, whereas FSEvents
monitors directories, not individual files. In your case, kqueues
may actually be more appropriate. Uli Kusterer has written a great Objective-C wrapper for kqueues. If you use this, you just need to start monitoring a particular file and you'll be notified whenever it changes via a delegate. This would be a simpler option if you only need to check one file at a time.
I hope this makes sense.
精彩评论