我有一个应用程序,可以查看传入作业的文件夹,然后处理它们。作业由文件夹中包含多个作业文件的文件夹组成。作业通常是通过互联网复制的,所以当一个文件夹被添加到我的监视文件夹时,我的应用程序获取作业文件夹中文件的属性,等待20秒,并比较NSFileSize的当前属性,看看是否有有任何改变。当一切都匹配,并且没有检测到任何更改时,它可以传递作业文件夹以进行处理。这是我的代码:
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;
}
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;
}
此代码在Lion中按预期工作,但是当我在Snow Leopard上运行App时,我得到NSFileSize属性的值不一致。每次循环运行时,我得到的值都比前一个循环完全不同。这显然是一个文件夹,其中包含不再被复制的文件,并且应该为文件大小提供匹配的值。
为什么这不适用于Snow Leopard,我需要做些什么才能解决这个问题?我的部分问题是我只在Lion Machine上进行开发,所以我必须进行构建,然后将其转移到雪豹机器上,而不需要调试器进行测试。这让我很难麻烦拍摄。
答案 0 :(得分:4)
这有一些问题,但首先,你是使用布尔运算符(!=
)比较两个对象的值。这是比较两个对象的指针位置,而不是它们的值。
要比较两个对象,您必须使用isEqual:
方法:
if (![[[jobFileAttrs objectAtIndex:i] objectForKey:NSFileSize] isEqual:[[jobFileAttrs2 objectAtIndex:i] objectForKey:NSFileSize]])
{
fileSizes = NO;
}
其次,这从根本上说是糟糕的设计。您的代码正在执行的操作称为轮询,代码中存在sleep()
是一个不好的信号。你永远不应该在Cocoa代码中使用sleep
,特别是如果你的代码在主线程上执行,因为它会阻塞主运行循环。
如果绝对必须使用轮询,则应使用NSTimer
对象。
但是,在这种特殊情况下,您不需要使用轮询来确定文件夹内容何时发生更改,您可以使用FSEvents
API代替。 API是基于C的,有点迟钝,所以你可能想要使用Stu Connolly的SCEvents
Objective-C wrapper.
您应该做的是维护当前文件的数组及其文件大小(可能是NSArray
实例变量,其中包含带有文件名和文件属性键的字典)然后当您收到通知时更改磁盘,获取文件的当前状态,并将其与存储的阵列中的信息进行比较。然后,您将使用更新的文件信息替换存储的数组。
其他文件监控选项为kqueues
。它们与FSEvents
的不同之处在于它们特定于特定文件,而FSEvents
监视目录,而不是单个文件。在您的情况下,kqueues
实际上可能更合适。 Uli Kusterer写了一篇很棒的Objective-C wrapper for kqueues。如果你使用它,你只需要开始监视一个特定的文件,并且只要它通过委托发生变化就会得到通知。如果您只需要一次检查一个文件,这将是一个更简单的选项。
我希望这是有道理的。