检查文件大小是否有变化

时间:2011-09-20 20:06:27

标签: objective-c cocoa

我有一个应用程序,可以查看传入作业的文件夹,然后处理它们。作业由文件夹中包含多个作业文件的文件夹组成。作业通常是通过互联网复制的,所以当一个文件夹被添加到我的监视文件夹时,我的应用程序获取作业文件夹中文件的属性,等待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上进行开发,所以我必须进行构建,然后将其转移到雪豹机器上,而不需要调试器进行测试。这让我很难麻烦拍摄。

1 个答案:

答案 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。如果你使用它,你只需要开始监视一个特定的文件,并且只要它通过委托发生变化就会得到通知。如果您只需要一次检查一个文件,这将是一个更简单的选项。

我希望这是有道理的。