文件檢索(Spotlight)

前言

Spotlight 是蘋(píng)果在Tiger(10.4)引入的一項(xiàng)快速搜索技術(shù),在Leopard中,Spotlight已經(jīng)無(wú)縫的整合進(jìn)入了Finder。從iOS3.0開(kāi)始,Spotlight被移植到了iOS。在OSX中,用戶(hù)點(diǎn)擊系統(tǒng)菜單欄右上角的??圖標(biāo)就可以使用Spotlight。在iOS中,用戶(hù)手指滑向主屏幕畫(huà)面左側(cè)就可以打開(kāi)類(lèi)似的窗口。

Spotlight背后實(shí)現(xiàn)機(jī)制是它有一個(gè)索引服務(wù)器mds,mds在MetaData框架中,MeteData框架是系統(tǒng)核心服務(wù)的一部分,其路徑是在

/SystemLibrary/Frameworks/CoreServices.framework/Frameworks/Metadata.framewrk.

mds是一個(gè)后臺(tái)服務(wù)的程序,每當(dāng)有文件被操作時(shí)(創(chuàng)建、修改和刪除)發(fā)生時(shí),內(nèi)核都會(huì)通知這個(gè)mds程序,這個(gè)通知機(jī)制叫做FSEvents,由于工作原因,我對(duì)相應(yīng)的api進(jìn)行的粗略的翻譯CoreServer文件系統(tǒng)監(jiān)控
。感興趣可以看一下。

當(dāng)mds收到FSEvents通知時(shí),mds會(huì)通過(guò)工作進(jìn)程(mdworker)將各種元數(shù)據(jù)信息導(dǎo)入數(shù)據(jù)庫(kù)。mdworker進(jìn)程可以加載一個(gè)具體的Spotlight Importer(Spotlight導(dǎo)入器)從文件中提前元數(shù)據(jù)。系統(tǒng)提供的導(dǎo)入器位于/System/Library/Spotlight目錄

[圖片上傳失敗...(image-70d3f9-1632396718794)]
用戶(hù)提供的導(dǎo)入器位于/Library/Spotlight目錄。我們可以通過(guò)構(gòu)建MeteData Importer模塊構(gòu)建,自定義Spotlight導(dǎo)入器,其官方文檔Spotlight Importer編程指南

通過(guò)命令行訪(fǎng)問(wèn)Spotlight

mdutil:管理元數(shù)據(jù)數(shù)據(jù)庫(kù)
mdfind:發(fā)出spotlight查詢(xún)

mdfind -name 1398

/Users/xxx/Library/Containers/com.tencent.xinWeChat/Data/Library/Application Support/com.tencent.xinWeChat/2.0b4.0.9/cd699567a64b554ba1d26d52add8b8db/Message/MessageTemp/8198a01c1bfa503859f285a1e1ef44af/Image/13981631266198_.pic_thumb.jpg

/Users/xxxx/Desktop/文件讀取測(cè)試/test221/1398.txt

/Users/xxx/Desktop/文件讀取測(cè)試/test221.bundle/1398.txt

/System/Library/PrivateFrameworks/Memories.framework/Versions/A/Resources/FlexAudio/18f501e0-4e5d-4af0-95ba-7ad429ee44d8.smsbundle/Summaries/139.83.summary

mdls:列出文件的元數(shù)據(jù)屬性

 mdls /Users/xxxx/Desktop/文件讀取測(cè)試/test221.bundle 

_kMDItemDisplayNameWithExtensions      = "test221.bundle"            //文件擴(kuò)展名
kMDItemContentCreationDate             = 2021-08-30 07:15:22 +0000   //文件內(nèi)容創(chuàng)建時(shí)間
kMDItemContentCreationDate_Ranking     = 2021-08-30 00:00:00 +0000
kMDItemContentModificationDate         = 2021-09-10 07:52:30 +0000   //文件內(nèi)容修改時(shí)間
kMDItemContentModificationDate_Ranking = 2021-09-10 00:00:00 +0000
kMDItemContentType                     = "com.apple.generic-bundle"  //文件內(nèi)容類(lèi)型
kMDItemContentTypeTree                 = (
    "com.apple.generic-bundle",
    "com.apple.bundle",
    "public.directory",
    "public.item",
    "com.apple.package"
)
kMDItemDateAdded                       = 2021-09-10 11:26:13 +0000 //文件添加時(shí)間
kMDItemDateAdded_Ranking               = 2021-09-10 00:00:00 +0000
kMDItemDisplayName                     = "test221.bundle"
kMDItemDocumentIdentifier              = 0
kMDItemFSContentChangeDate             = 2021-09-10 07:52:30 +0000 //內(nèi)容修改時(shí)間
kMDItemFSCreationDate                  = 2021-08-30 07:15:22 +0000
kMDItemFSCreatorCode                   = ""
kMDItemFSFinderFlags                   = 0
kMDItemFSHasCustomIcon                 = (null)
kMDItemFSInvisible                     = 0=
kMDItemFSIsExtensionHidden             = 0
kMDItemFSIsStationery                  = (null)
kMDItemFSLabel                         = 0
kMDItemFSName                          = "test221.bundle"
kMDItemFSNodeCount                     = 8
kMDItemFSOwnerGroupID                  = 20
kMDItemFSOwnerUserID                   = 501
kMDItemFSSize                          = 278040
kMDItemFSTypeCode                      = ""
kMDItemInterestingDate_Ranking         = 2021-09-10 00:00:00 +0000  //文件種類(lèi)
kMDItemKind                            = "捆綁包"
kMDItemLogicalSize                     = 278040                     //文件大小 字節(jié)
kMDItemPhysicalSize                    = 303104

mdimport:配置和測(cè)試spotlight插件

代碼實(shí)現(xiàn)Spotlight檢索

兩種實(shí)現(xiàn)方式

  • 使用MDQuery(CoreSerive.framework)類(lèi),里面提供的都是C語(yǔ)言編寫(xiě)的,并且僅提供在OSX上使用
  • 使用NSMetaDataQuery(CoreFoundation中)類(lèi)。是蘋(píng)果提供的一層對(duì)MDQuery封裝的高級(jí)API。相比MDQuery不支持同步查詢(xún)。并在收集數(shù)據(jù)時(shí)提供最少的更新通知。

使用NSMetaDataQuery實(shí)現(xiàn)文件檢索

執(zhí)行異步元數(shù)據(jù)查詢(xún)主要有四個(gè)步驟:

1.定義和初始化搜索

  1. 創(chuàng)建一個(gè)NSMetadataQuery實(shí)例。
  2. 注冊(cè)接收NSMetadataQueryDidUpdateNotification批量搜索內(nèi)容返回時(shí)發(fā)送的通知根據(jù)批次值,可能不會(huì)生成此通知。
  3. 注冊(cè)以接收NSMetadataQueryDidFinishGatheringNotification初始搜索完成時(shí)發(fā)送的通知。

2.設(shè)置搜索

2.1 設(shè)置查詢(xún)語(yǔ)句

NSPredicate使用適當(dāng)?shù)?Spotlight 查詢(xún)表達(dá)式創(chuàng)建一個(gè)實(shí)例。

2.2 設(shè)置排序順序

可以通過(guò)提供排序描述符數(shù)組來(lái)指定結(jié)果的排序順序。排序基于每個(gè)返回NSMetadataItem對(duì)象的元數(shù)據(jù)屬性鍵。使用所需的元數(shù)據(jù)鍵創(chuàng)建一個(gè) NSSortDescriptor 進(jìn)行排序,在本例中為kMDItemDisplayName。

2.3 設(shè)置搜索范圍

應(yīng)用程序通過(guò)指定搜索范圍來(lái)限制從何處收集搜索結(jié)果。
搜索范圍指定元數(shù)據(jù)查詢(xún)搜索文件的位置。

范圍常數(shù) 支持的操作系統(tǒng) 描述
NSMetadataQueryUbiquitousDocumentsScope iOS 和 OS X 搜索應(yīng)用程序 iCloud 容器目錄的 Documents 目錄中的所有文件。
NSMetadataQueryUbiquitousDataScope iOS 和 OS X 搜索不在應(yīng)用程序 iCloud 容器目錄的 Documents 目錄中的所有文件。
NSMetadataQueryNetworkScope 操作系統(tǒng) 搜索所有用戶(hù)安裝的遠(yuǎn)程卷。
NSMetadataQueryLocalComputerScope 操作系統(tǒng) 搜索所有本地安裝的卷,包括用戶(hù)主目錄。即使是遠(yuǎn)程卷,也會(huì)搜索用戶(hù)的主目錄。
NSMetadataQueryUserHomeScope 操作系統(tǒng) 搜索用戶(hù)的主目錄。

注意:在 OS X 上,雖然文件系統(tǒng)元數(shù)據(jù)在所有卷上可用,但其他元數(shù)據(jù)屬性不可用。Spotlight 不會(huì)為 CD、DVD、磁盤(pán)映像和系統(tǒng)目錄編制索引。

3.啟動(dòng)搜索

創(chuàng)建并配置查詢(xún)對(duì)象后,您可以通過(guò)調(diào)用startQuery函數(shù)執(zhí)行查詢(xún)。

運(yùn)行時(shí),查詢(xún)通常有兩個(gè)階段:初始結(jié)果收集階段和實(shí)時(shí)更新階段。
在初始結(jié)果收集階段,會(huì)在現(xiàn)有 Spotlight系統(tǒng)存儲(chǔ)中搜索與搜索表達(dá)式匹配的文件。當(dāng)結(jié)果使用NSMetadataQueryDidUpdateNotification. 在單個(gè)查詢(xún)中,這對(duì)于指示搜索進(jìn)度的狀態(tài)很有用,而在實(shí)時(shí)搜索中它變得更加重要。
NSMetadataQueryDidFinishGatheringNotification當(dāng)初始結(jié)果收集階段完成時(shí),查詢(xún)向應(yīng)用程序發(fā)送通知。

4.訪(fǎng)問(wèn)返回結(jié)果

在您的應(yīng)用程序與返回的結(jié)果交互之前,它必須首先停止查詢(xún)。

您可以在搜索的初始收集階段或?qū)崟r(shí)更新階段禁用更新。應(yīng)用程序通過(guò)調(diào)用NSMetadataQuery實(shí)例方法確定已返回的結(jié)果數(shù)resultCount。然后,應(yīng)用程序使用resultAtIndex:方法請(qǐng)求所需索引處的結(jié)果項(xiàng)。

結(jié)果項(xiàng)作為類(lèi)型的對(duì)象實(shí)例返回NSMetadataItem。每個(gè)對(duì)象都封裝了文件的元數(shù)據(jù)屬性。
然后,您的應(yīng)用程序通過(guò)向每個(gè)實(shí)例valueForAttribute:傳遞帶有所需元數(shù)據(jù)屬性名稱(chēng)的消息,從這些項(xiàng)目中檢索元數(shù)據(jù)屬性。

5.NSMetadataQuery代碼示例


// 初始化搜索方法
- (void)initiateSearch {
     //1.初始化創(chuàng)建搜索
    self.metadataSearch = [[NSMetadataQuery alloc] init];
     //注冊(cè)通知監(jiān)聽(tīng)
    [self addQueryObserver];

    //2.設(shè)置查詢(xún)
    //2.1 設(shè)置查詢(xún)語(yǔ)句
    NSPredicate *searchPredicate =[NSPredicate predicateWithFormat:@"kMDItemDisplayName == 'fileName'"];
    [metadataSearch setPredicate:searchPredicate];
  
    //2.2 設(shè)置排序順序,以便對(duì)查詢(xún)結(jié)果進(jìn)行排序
    NSSortDescriptor *sortKeys = [[[NSSortDescriptor alloc] initWithKey:(id)kMDItemDisplayName
                                                            升序:是] 自動(dòng)釋放];
    [metadataSearch setSortDescriptors:[NSArray arrayWithObject:sortKeys]];
 
    //2.3 設(shè)置搜索范圍
    NSArray *searchScopes = [NSArray arrayWithObjects:NSMetadataQueryUserHomeScope,
                  NSMetadataQueryUbiquitousDocumentsScope,nil];
    [metadataSearch setSearchScopes:searchScopes];

    //3.開(kāi)啟異步查詢(xún)
    [metadataSearch startQuery];
 
}

- (void)addQueryObserver {
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(initalGatherComplete:) name:NSMetadataQueryDidFinishGatheringNotification object:_metaDataSearch];
}
- (void)removeQueryObserver {
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:_metaDataSearch];
}
// 初始查詢(xún)收集完成時(shí)調(diào)用的方法
- (void)initalGatherComplete:sender;
{
    // 停止查詢(xún),單遍完成。
    [_metaDataSearch stopQuery];
 
    // 處理內(nèi)容。在這種情況下,應(yīng)用程序只需迭代內(nèi)容,打印顯示名稱(chēng)鍵
    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);
    }
 
    // 刪除通知以在我們自己之后清理。
    // 同時(shí)釋放metadataQuery。
    // 當(dāng) Query 被移除時(shí),查詢(xún)結(jié)果也會(huì)丟失。
    [self removeQueryObserver];
    self.metaDataSearch = nil;
}

文件查詢(xún)語(yǔ)句規(guī)則

文件元數(shù)據(jù)查詢(xún)語(yǔ)句規(guī)則

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容