【问题标题】:Returning a list of directories with NSMetadataQuery and NSPredicate使用 NSMetadataQuery 和 NSPredicate 返回目录列表
【发布时间】:2011-12-14 00:14:35
【问题描述】:

我正在尝试获取用户 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]);

...

【问题讨论】:

    标签: iphone objective-c ios5 nspredicate icloud


    【解决方案1】:

    我已经尝试了 EmptyStack 的答案,但没有运气......

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

    但是,至少有一种解决此问题的方法:

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

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

    我们使用谓词进行查询:

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

    结果将是(使用 NSMetadataItemURLKey 获取 URL)

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

    我们需要做的是通过查看每个 URL 的组件数量并根据需要对 URL 进行切分来自行过滤这些结果。第一级的项目应该有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];
    

    【讨论】:

    • :我使用了 predicateWithFormat:@"%K BEGINSWITH %@", NSMetadataItemPathKey, dirPath];但我没有给所有的文件夹。你能告诉我你是怎么做到的吗?我还想显示 icloud 帐户中的所有目录和文件。
    【解决方案2】:

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

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

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

    如果你想获取所有文件而不考虑它们的扩展名,只需在上面的谓词中添加 NOT 关键字,

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

    【讨论】:

    • 谢谢。我做了一个 NSLog(@"Query count %i", [query resultCount]);但即使有两个目录,它也不会显示任何结果。它会找到所有 txt 文件,但不会找到目录。有没有办法列出所有文件,无论它们的扩展名或结尾?
    • 如果您希望所有文件都将谓词更改为此@"NOT %K.pathExtension = ''"
    • 谢谢,但它仍然没有列出我的目录。我通过转到 Lion 中的 Mobile Documents 来检查它是否真的存在。该文件夹称为 myTXTs ,即使我将谓词更改为 predicateWithFormat: @"%K == %@", NSMetadataItemFSNameKey, @"myTXTs" 计数也会返回 0。有什么想法吗?看起来好像目录根本不存在 - 尽管存在!
    • 我更新了上面的代码——也许我在计算查询时做错了。感谢您的帮助。
    【解决方案3】:

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

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

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

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

    【讨论】:

    • 不幸的是,“元数据框架”在 iOS SDK 中不可用(从 iOS6 开始)。 iOS 仅提供 Objective-C 元数据搜索接口。程序 C 版本仅在 OS X 上可用。 这意味着我们,第 3 方开发者,必须使用 NSMetadaQuery、NSMetadataItem 等,而不是它们的低级计数器部分 MDQuery 等developer.apple.com/library/mac/#documentation/Carbon/…
    【解决方案4】:

    试试这个:

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

    它对我有用。

    【讨论】:

    • 看起来这将返回一个文本文件列表,而不是目录,不是吗?
    猜你喜欢
    • 2014-02-08
    • 2013-09-02
    • 1970-01-01
    • 2017-02-14
    • 2012-05-31
    • 2016-12-06
    • 2012-12-30
    • 1970-01-01
    • 2012-11-10
    相关资源
    最近更新 更多