使用NSMetadataQuery和NSPredicate返回目录列表

时间:2011-10-24 10:03:25

标签: iphone objective-c ios5 nspredicate icloud

我正在尝试获取用户的iCloud文件夹中的目录列表。我找到了如何寻找特殊类型的文件(如txt文件),它工作正常:

NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
_query = query;

//Search all files in the Documents directories of the application’s iCloud container directories:
[query setSearchScopes:[NSArray arrayWithObject:NSMetadataQueryUbiquitousDocumentsScope]]; 

NSPredicate *pred = [NSPredicate predicateWithFormat:@"%K ENDSWITH '.txt'", NSMetadataItemFSNameKey];

[query setPredicate:pred];
[query startQuery];

但是,我现在只想获取目录。我已经阅读了有关NSPredicate的文档,但我不知道如何寻找目录。我想NSPredicate不是为此而做的?我可以检查是否有像这样的目录:

    BOOL isDir;
BOOL exists = [fm fileExistsAtPath:path isDirectory:&isDir];
if (exists) {
    /* file exists */
    if (isDir) {
        /* file is a directory */
    }
 }

但是如何将它应用于NSMetadataQuery,我不知道。如果能得到任何帮助,我将不胜感激。


编辑:

我将谓词更改为[NSPredicate predicateWithFormat:@"%K.pathExtension = ''", NSMetadataItemFSNameKey];

然后我确定查询的完成时间如下:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(queryDidFinishGathering:) name:NSMetadataQueryDidFinishGatheringNotification object:query];
[query startQuery];

- (void)queryDidFinishGathering:(NSNotification *)notification {

NSMetadataQuery *query = [notification object];
[query disableUpdates]; // You should invoke this method before iterating over query results that could change due to live updates.
[query stopQuery]; // You would call this function to stop a query that is generating too many results to be useful but still want to access the available results.

[self loadData:query];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
_query = nil; // we're done with it

}

最后,我做了一个计数,但是这总是会给我0但是我在云端的目录很多(我通过Lion和Mobile Documents文件夹检查了这个;例如我有Documents / myTXTs等)。这很奇怪。如果我对文本文件进行计数,它会给我4,因为我有4个txt文件。所以我想我的目录没有被计算在内:

 - (void)loadData:(NSMetadataQuery *)query {

    NSLog(@"Query count %i", [query resultCount]);

...

4 个答案:

答案 0 :(得分:5)

我没有运气就尝试过EmptyStack的答案....

我发现 NSMetadataQuery找不到目录,问题不在于NSPredicate是从结果中过滤目录,问题只是查询''找到文件夹。我已经尝试使用调试器,发现找到的所有LBItem都是常规文件而不是目录。我希望Apple将来能够改进这一点。 也许在MountainLion中这是更好的,因为他们似乎有文件夹支持......哎呀当然你没有在这里读到这个,因为它仍然是NDA。算了吧

然而,至少有一种解决方法:

例如,如果您的文件结构是;

|_Folder
| |_file
| |_file2
|_Folder1
| |_file
|_file

我们使用谓词进行查询:

predicateWithFormat:@"%K LIKE '*'", NSMetadataItemFSNameKey

结果将是(使用NSMetadataItemURLKey获取网址)

path/to/iCloud/Documents/Folder/file
path/to/iCloud/Documents/Folder/file2
path/to/iCloud/Documents/Folder1/file
path/to/iCloud/Documents/file

我们需要做的是通过查看每个网址的组件数量并根据需要切断网址来自行过滤这些结果。第一级的项目应该有numberOfComponentsOfUbiquitousContainer + 1,下一级的项目应该有一个,依此类推。 我们也需要丢弃重复(或者在这个例子中我们会得到Folder两次)。

可能不是最佳但对我有用,

更新

最好使用下面的谓词,它会在抓取子文件夹时减少查询结果。

// dirPath is an NSString path of the directory you want
// to look at. Usually, for the top level directory:
// [NSFileManager URLForUbiquityContainerIdentifier:nil].path;
predicateWithFormat:@"%K BEGINSWITH %@", NSMetadataItemPathKey, dirPath];

答案 1 :(得分:1)

如果您只想获取目录,请使用以下谓词。

predicateWithFormat:@"%K.pathExtension = ''", NSMetadataItemFSNameKey

请注意,这并不能保证您只使用此方法获取目录,因为(我已经看到一些)没有扩展名的文件。但如果您确定所有文件都有扩展名,那么您可以很好地使用它。

如果您想获取所有文件,无论其扩展名如何,只需将NOT关键字添加到上述谓词中,

predicateWithFormat:@"NOT %K.pathExtension = ''", NSMetadataItemFSNameKey

答案 2 :(得分:0)

试试这个:

[query setPredicate:[NSPredicate predicateWithFormat:@"%K like '*.txt'", NSMetadataItemFSNameKey]];

它对我有用。

答案 3 :(得分:0)

您可以使用MDQuery执行此操作 - 这是NSMetadataquery使用的“真实”代码。

在“终端”中,键入“mdls”,然后在文件夹中拖动。然后键入mdfind并使用提供的示例仅将kMDItemContentType类型树更改为public.folder - 您将获得大量结果。

然后在代码中执行此操作,您需要遵循MDQueryRef示例。代码流与Cocoa相同,我发现查询更容易创建和理解。您可以将可可回调设置为MDQuery - 因此它与NSMetadataquery的兼容性非常好。

NSMetadataQuery有一些我认为不在MDQuery中的iCloud内容。所以我认为它们并不相同。