Apple - File Metadata Search Programming Guide 文件元数据搜索

本文翻译整理自:File Metadata Search Programming Guide(更新日期:2011-09-28

https://developer.apple.com/library/archive/documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction.html#//apple_ref/doc/uid/TP40001841



一、关于文件元数据查询

文件元数据提供了几个应用程序编程接口,允许it应用程序根据文件或文件系统的数据搜索文件。
您的应用程序与搜索结果所需的交互级别通常会决定您选择的API。

在Mac应用程序中提供元数据支持的最简单方法是使用Spotlight搜索窗口。
使用此API,应用程序可以显示标准Spotlight搜索窗口,可选地提供搜索字符串。
搜索结果直接呈现给用户,应用程序无法使用。
如果您的应用程序不是面向搜索的,但您希望允许用户使用Spotlight搜索上下文术语,这是一个不错的选择。

对于需要创建查询并与结果交互的应用程序,有两种API可用。
元数据框架提供了一个低级查询APIMDQuery,它允许应用程序根据元数据值搜索文件。
MDQuery是完全可配置的,允许您运行同步和异步查询,并提供对结果批处理频率的细粒度控制。

Cocoa框架的NSMetadataQuery类为MDQueryAPI提供了一个高级Objective-C接口。
此类允许您使用NSPredicate类的子集构建查询,并异步执行查询。
NSMetadataQuery类允许应用程序指定将结果分组为多个子类别。
NSMetadataQuery不支持同步查询,并在收集数据时提供最少的更新通知。
在OS X上NSMetadataQuery支持Cocoa绑定,允许您显示结果而无需编写任何大量的胶水代码。

注意:iOS仅提供Objective-C元数据搜索接口。
过程C版本仅在OS X上可用。


1、谁应该阅读此文档

Spotlight是OS X的一个基本特性,所有开发人员都应该熟悉它的功能。
许多应用程序至少应该为用户提供使用Spotlight搜索窗口搜索选定文本的能力。


2、本文件的组织

以下文章介绍了了解如何使用Spotlight查询元数据的关键概念:


3、另见

对于将元数据集成到您的应用程序中,还有其他技术,本文档没有完全介绍。
有关更多详细信息,请参阅这些文档:


以下示例代码可用于显示如何生成Spotlight查询。

  • Spotlight 示例展示了如何使用Spotlight搜索。
  • PredicateEditorSample 演示如何使用规则编辑器和Spotlight。
  • PhotoSearch 允许根据名称搜索图像。
    它允许同时运行多个搜索。

二、搜索iCloud和桌面

Spotlight搜索功能可在iOSv5.0和OS X上使用。
使用这些搜索查询iOS可以搜索iCloud内容,OS X可以搜索iCloud、桌面和网络文件。


1、OS X搜索功能

Spotlight在OS X上无处不在。
Finder使用它来搜索允许用户搜索文件。
Mail在搜索过程中使用Spotlight查找消息,任何应用程序都可以使用Spotlight搜索用户的主目录、本地文件系统、任何附加的网络文件系统和iCloud。

Spotlight API的OS X Objective-C接口包括用于搜索(NSMetadataQuery)、检查文件元数据(NSMetadataItem)的类,以及让NSMetadataQuery使用NSMetadataQueryAttributeValueTuple类返回更复杂的数据集的能力。
此外,存在一个对应于每个Objective-C类的Core Foundation API(事实上,这些类是基于Core Foundation基础构建的)。


注意:依靠文件元数据非常有用。
它允许您检索有关各种文件属性的信息,例如,视频帧大小、声音文件压缩、Finder注释、文件作者等等,而无需知道如何读取文件格式。
请注意,用户可以根据每个卷或文件夹禁用Spotlight。


2、iOS搜索功能

iOS允许在iCloud内元数据搜索以查找文件对应的文件。
它仅提供文件元数据查询的Objective-C接口NSMetadataQueryNSMetadataItem,以及仅支持搜索iCloud的搜索范围。

与桌面不同,iOS应用程序的沙盒无法使用元数据类进行搜索。
为了搜索应用程序的沙盒,您需要使用NSFileManager类递归遍历沙盒文件系统中的文件。
一旦找到匹配的文件,您可以按照需要的方式访问该文件。
您还可以使用NSMedatataItem类来检索该特定文件的元数据。


三、使用NSMetadataQuery搜索文件元数据

为了让您的应用程序搜索Spotlight元数据,您必须使用Foundation框架提供的NSMetadataQuery类创建查询。
查询可以在两种模式下运行:异步和异步实时更新。
第一种模式只是对初始搜索时存在的文件执行搜索。
后者继续搜索。
将数据更新为满足或不再满足搜索参数更新的文件。

执行异步元数据查询有四个主要步骤:

  • 定义和初始化搜索。
  • 启动搜索。
  • 侦听批处理通知。
  • 监听完成通知。
  • 停止查询。
  • 处理结果。

实时异步Spotlight查询允许您的应用程序监视指定范围内动态发生的更改。
代码中唯一重要的区别是,您只需在处理结果时暂停查询,然后在处理完成后恢复搜索,而不是停止查询。


1、创建静态文件元数据搜索

静态Spotlight搜索是一种简单运行、返回结果并退出的搜索。
它旨在作为不监控更改的一次性搜索(这可以使用实时搜索,在创建实时搜索中讨论。


定义搜索

创建查询的第一步是定义返回所需结果的搜索表达式。
如果您使用MDMetadataQuery执行查询,请使用文件元数据查询表达式语法中描述的语法创建搜索表达式谓词。
您必须注册通知,以便在返回数据批次和初始搜索完成时通知您。
您还可以选择注册范围、排序和委托。


定义搜索

  1. 创建一个NSMetadataQuery实例。
  2. 注册以接收返回批量搜索内容时发送的NSMetadataQueryDidUpdateNotification通知。
    根据批次值,可能不会生成此通知。
  3. 注册以接收初始搜索完成时发送的NSMetadataQueryDidFinishGatheringNotification通知。

设置查询搜索

使用文件元数据查询表达式语法中指定的语法创建搜索谓词。
可以搜索的字段在*文件元数据属性引用*中定义。
属性引用列出了可用的元数据键和搜索该属性必须提供的数据类型(字符串、数字、字符串数组、日期或统一类型标识符)。


创建查询

  • 使用适当的Spotlight查询表达式创建NSPredicate实例。

设置排序顺序

如果使用的是NSMetadataQuery,可以通过提供排序描述符数组来指定结果的排序顺序,排序基于每个返回的NSMetadataItem对象的元数据属性键。


设置搜索顺序

  • 使用所需的元数据键创建NSSortDescriptor进行排序,在本例中为kMDItemDisplayName

限制搜索范围

应用程序通过指定搜索范围来限制搜索结果的收集位置。
搜索范围作为预定义位置常量、URL和目录路径的数组提供给查询。
预定义位置常量提供方便的值,用于将查询限制在用户的主目录、本地安装的卷和用户的主目录或远程安装的卷。

搜索范围指定元数据查询搜索文件的位置。


表2-1支持的搜索范围

范围常数支持的操作系统描述
NSMetadataQueryUbiquitousDocumentsScopeiOS和OS X搜索应用程序iCloud容器目录的Documents目录中的所有文件。
NSMetadataQueryUbiquitousDataScopeiOS和OS X搜索不在应用程序iCloud容器目录的Documents目录中的所有文件。
NSMetadataQueryNetworkScopeOS X搜索所有用户安装的远程卷。
NSMetadataQueryLocalComputerScopeOS X搜索所有本地挂载的卷,包括用户主目录。
即使是远程卷,也会搜索用户的主目录。
NSMetadataQueryUserHomeScopeOS X搜索用户的主目录。

搜索范围被指定为范围常量的数组。


指定搜索范围

  • NSMetadataSearch实例发送setSearchScopes:消息,传递适当范围的数组。
    此查询将搜索计算机上的用户目录以及iCloud文档文件夹。只需删除不受支持的NSMetadataQueryUserHomeScope范围常量,即可在iOS上运行相同的搜索代码。

注意:重要的是要记住,在OS X上,虽然文件系统元数据在所有卷上都可用,但其他元数据属性不可用。
CD、DVD、磁盘映像和系统目录不会被Spotlight索引。

用户还可以使用Spotlight首选项显式排除特定目录和文档类型的返回结果。
iOS只能使用常规->Spotlight搜索下的设置应用程序中的Spotlight搜索选项从搜索结果中删除文档类型。


运行搜索

创建和配置查询对象后,您可以自行执行查询。
运行时,查询通常有两个阶段:初始结果收集阶段和实时更新阶段。

在初始结果收集阶段,将在现有的Spotlight系统存储中搜索与搜索表达式匹配的文件。
当使用NSMetadataQueryDidUpdateNotification批量返回结果时,查询会发送通知。
在单个查询中,这对于指示搜索进度状态很有用,而在实时搜索中,这变得更加重要。

初始结果收集阶段完成后,查询会向应用程序发送NSMetadataQueryDidFinishGatheringNotification 通知。

要运行搜索,请向NSMetadataSearch实例 发送startQuery消息。


访问返回的结果

在您的应用程序与返回的结果交互之前,它必须首先停止查询。
您可以在搜索的初始收集阶段或实时更新阶段禁用更新。

应用程序通过调用NSMetadataQuery实例方法resultCount来确定返回的结果数。
然后,应用程序通过索引位置访问单个结果项。
与其遍历results(用于Cocoa Bindings),不如使用结果resultAtIndex:方法在所需索引处请求结果项。

结果项作为NSMetadataItem类型的对象实例返回。
每个对象都封装了文件的元数据属性。
然后,应用程序通过向每个实例传递带有所需元数据属性名称的valueForAttribute:消息来从这些项中检索元数据属性。


访问结果

  1. 停止正在进行的查询。
  2. 遍历结果,执行适合您的应用程序的任何操作。
  3. 删除通知的观察者。

如果您打算多次运行查询,则此步骤是可选的。但是,如果您打算使用相同的设置代码,您可能希望无论如何都删除观察者。


完成的静态搜索

创建静态文件元数据搜索显示实现静态搜索所需的代码。


例2-1静态Spotlight搜索实现

// Initialize Search Method
- (void)initiateSearch
{
    // Create the metadata query instance. The metadataSearch @property is
    // declared as retain
    self.metadataSearch=[[[NSMetadataQuery alloc] init] autorelease];
 
    // Register the notifications for batch and completion updates
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(queryDidUpdate:)
                                                 name:NSMetadataQueryDidUpdateNotification
                                               object:metadataSearch];
 
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(initalGatherComplete:)
                                                 name:NSMetadataQueryDidFinishGatheringNotification
                                               object:metadataSearch];
 
    // Configure the search predicate to find all images using the
    // public.image UTI
    NSPredicate *searchPredicate;
    searchPredicate=[NSPredicate predicateWithFormat:@"kMDItemContentTypeTree == 'public.image'"];
    [metadataSearch setPredicate:searchPredicate];
 
    // Set the search scope. In this case it will search the User's home directory
    // and the iCloud documents area
    NSArray *searchScopes;
    searchScopes=[NSArray arrayWithObjects:NSMetadataQueryUserHomeScope,
                  NSMetadataQueryUbiquitousDocumentsScope,nil];
    [metadataSearch setSearchScopes:searchScopes];
 
    // Configure the sorting of the results so it will order the results by the
    // display name
    NSSortDescriptor *sortKeys=[[[NSSortDescriptor alloc] initWithKey:(id)kMDItemDisplayName
                                                            ascending:YES] autorelease];
    [metadataSearch setSortDescriptors:[NSArray arrayWithObject:sortKeys]];
 
    // Begin the asynchronous query
    [metadataSearch startQuery];
 
}
 
// Method invoked when notifications of content batches have been received
- (void)queryDidUpdate:sender;
{
    NSLog(@"A data batch has been received");
}
 
 
// Method invoked when the initial query gathering is completed
- (void)initalGatherComplete:sender;
{
    // Stop the query, the single pass is completed.
    [metadataSearch stopQuery];
 
    // Process the content. In this case the application simply
    // iterates over the content, printing the display name key for
    // each image
    NSUInteger i=0;
    for (i=0; i < [metadataSearch resultCount]; i++) {
        NSMetadataItem *theResult = [metadataSearch resultAtIndex:i];
        NSString *displayName = [theResult valueForAttribute:(NSString *)kMDItemDisplayName];
        NSLog(@"result at %lu - %@",i,displayName);
    }
 
    // Remove the notifications to clean up after ourselves.
    // Also release the metadataQuery.
    // When the Query is removed the query results are also lost.
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSMetadataQueryDidUpdateNotification
                                                  object:metadataSearch];
    [[NSNotificationCenter defaultCenter] removeObserver:self
                                                    name:NSMetadataQueryDidFinishGatheringNotification
                                                  object:metadataSearch];
    self.metadataSearch=nil;
}
 
@end


2、创建实时搜索

实时搜索以虚拟的方式配置为仅进行少量更改的相同搜索。

  • 在访问更新的数据之前,必须使用disableUpdates暂停查询。
  • 数据通常以某种形式在queryDidUpdate:方法中处理。
  • 然后使用enableUpdates重新启动查询以继续搜索。

四、文件元数据查询表达式语法

文件元数据查询使用作为谓词字符串格式子集的查询语言构建。
元数据搜索表达式语法允许应用程序“即时”构建搜索,允许高级用户构建自己的查询,或者您的应用程序存储常用查询以便于使用。
语法相对简单,包括比较、与语言无关的选项以及时间和日期变量。


比较语法

文件元数据查询表达式语法是shell用户熟悉的文件名全局化的简化形式。
查询具有以下格式:

attribute == value

其中attribute是标准元数据属性(参见*文件元数据属性参考*)或由导入器定义的自定义元数据属性。

例如,要查询Spotlight以获取“Steve”创作的所有文件,查询如下所示:

kMDItemAuthors ==[c] "Steve"

表3-1列出了可用的比较运算符。


Table 3-1 Comparison operators

算子描述
==相等
!=不相等
<小于(仅适用于数值和日期)
>大于(仅适用于数值和日期)
<=小于或等于(仅适用于数值和日期)
>=大于或等于(仅适用于数值和日期)
InRange(attributeName,minValue,maxValue)指定属性名称中minValue到maxValue范围内的数值

值字符串中的等字符应使用\字符进行转义。

示例中的搜索值有修饰符“c”。
这些修饰符指定如何进行比较。
表3-2描述了可用的比较修饰符。

搜索修饰符应紧跟在比较运算符之后,并用方括号[…]括起来。


Table 3-2 Value Comparison modifiers

修改描述
c比较不区分大小写。
d这种比较对变音符号不敏感。

表3-3显示了几个使用比较修饰符的示例。

Table 3-3 Value Comparison modifier examples

查询字符串结果
kMDItemTextContent == "Paris"匹配“巴黎”但不匹配“巴黎”。
kMDItemTextContent ==[c] "Paris"匹配“巴黎”和“巴黎”。
kMDItemTextContent ==[c] "*Paris*"匹配“Paris”、“paris”、“I love Paris”和“paris-French. jpg”。
kMDItemTextContent == "Frédéric"匹配“Frédéric”但不匹配“Frederic”。
kMDItemTextContent ==[d] "Frédéric"无论单词case如何,都匹配“Frédéric”和“Frederic”。

使用通配符(*?),您可以在字符串的开头、结尾或字符串中的任何位置匹配子字符串。
表3-4显示了几种常见用法。

字符*匹配多个字符,而?通配符匹配单个字符。


Table 3-4 Using wildcards

查询字符串结果
kMDItemTextContent == "paris*"匹配以“paris”开头的属性值。
例如,匹配“paris”,但不匹配“比较”。
kMDItemTextContent == "*paris"匹配以“paris”结尾的属性值。
kMDItemTextContent == "*paris*"匹配值中任何位置包含“paris”的属性。
例如,匹配“paris”和“比较”。
kMDItemTextContent == "paris"匹配完全等于“paris”的属性值。

可以使用类似C的语法组合查询AND&&)和OR||)。
例如,要将查询限制为“史蒂夫”创作的音频文件,查询将是:

kMDItemAuthors ==[c] "Steve" && kMDItemContentType == "public.audio"

括号可用于进一步组查询匹配。
例如,要搜索由“Steve”或“Daniel”创作的音频文件,查询将是:

(kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors[c] == "Steve") &&
 kMDItemContentType == "public.audio"

您可以使用以下查询扩展此搜索以包含视频文件:

(kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors ==[c] "Steve" ) &&
 (kMDItemContentType == "public.audio" || kMDItemContentType == "public.video")

时间和日期变量

您还可以创建使用日期和时间作为搜索值的查询。
日期和时间值被格式化为与CFDate兼容的浮点值,相对于2001年1月1日为秒。

此外,还提供了$time变量,可用于指定相对于当前时间的值,如表3-5所示。


Table 3-5 $time variable expressions

时间变量描述
$time.now当前日期和时间。
$time.today当前日期。
$time.yesterday昨天的日期。
$time.this_week(-1)前一周的日期。
$time.this_week本周的日期。
$time.this_month当前月份的日期。
$time.this_year当年的日期。
$time.now(NUMBER)通过将正值或负值(以秒为单位)添加到当前时间的日期和时间。
$time.today(NUMBER)通过将正值或负值(以天为单位)添加到当前日期的日期
$time.this_week(NUMBER)通过向当前周添加正值或负值(以周为单位)来确定日期。
$time.this_month(NUMBER)通过将正值或负值(以月为单位)添加到当前月份的日期。
$time.this_year(NUMBER)通过在当前年份中添加正值或负值(以年为单位)来确定日期。
$time.iso(ISO-8601-STR)通过解析指定的ISO-8601-STR兼容字符串的日期。

使用$time变量,您可以使用以下查询将搜索限制为仅查找上周更改的文件:

((kMDItemAuthors ==[c] "Daniel" || kMDItemAuthors[c] == "Steve") &&
 (kMDItemContentType == "public.audio" || kMDItemContentType == "public.video")) &&
 (kMDItemFSContentChangeDate == $time.this_week(-1))

注意: 第一次执行查询时设置了$time变量的值。
随着查询继续运行,它不会更新到当前时间。


五、显示Finder的Spotlight搜索窗口

应用程序可以通过显示标准的Finder搜索界面为用户提供与Spotlight的直接交互。

NSWorkspace方法showSearchResultsForQueryString:为Finder搜索窗口提供了一个简单的界面。
这在编程上相当于用户切换到Finder,创建一个新窗口,并在搜索字段中键入搜索字符串。

显示Finder的Spotlight Search Window中的代码片段演示了提取字符串值并显示搜索界面。

例4-1显示Finder搜索窗口

resultCode=[[NSWorkspace sharedWorkspace] showSearchResultsForQueryString:[sender stringValue]];
 
if (resultCode == NO) {
    // failed to open the panel
    // present an error to the user
    }


2024-06-16(日) |

  • 17
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI工程化

请我喝杯伯爵奶茶~!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值