Возвращение списка каталогов с помощью NSMetadataQuery и NSPredicate - PullRequest
2 голосов
/ 24 октября 2011

Я пытаюсь получить список каталогов в папке пользователя iCloud. Я разработал, как искать специальные типы файлов (например, текстовые файлы), и он отлично работает:

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, я понятия не имею. Я был бы благодарен за любую помощь, которую я могу получить.


EDIT:

Я изменил предикат на [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 текстовых файла. Поэтому я думаю, что мои каталоги не учитываются:

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

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

...

Ответы [ 4 ]

5 голосов
/ 09 мая 2012

Я попробовал ответ EmptyStack без удачи ....

Я обнаружил, что NSMetadataQuery НЕ находит каталоги , Проблема не в том, NSPredicate фильтрует каталоги по результатам, проблема просто в том, что запрос не находит папки. Я попробовал с отладчиком и обнаружил, что все найденные LBItem имеют обычные файлы, а не каталоги. Я надеюсь, что Apple улучшит это в будущем. Может быть, в 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];
1 голос
/ 24 октября 2011

Если вы хотите получить только каталоги, используйте следующий предикат.

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

Обратите внимание, что это не гарантирует, что вы получите только каталоги, используя этот метод, как есть (I 'Видел некоторые) файлы, которые не имеют расширений.Но если вы уверены, что все ваши файлы имеют расширения, вы можете очень хорошо использовать это.

Если вы хотите получить все файлы независимо от их расширения, просто добавьте ключевое слово NOT к вышеуказанному предикату,

predicateWithFormat:@"NOT %K.pathExtension = ''", NSMetadataItemFSNameKey
0 голосов
/ 04 июня 2012

Вы можете сделать это с помощью MDQuery - «реального» кода, который использует NSMetadataquery.

В Терминале введите «mdls», затем перетащите в папку.Затем введите mdfind и в приведенном примере измените только дерево типов kMDItemContentType на public.folder - вы получите множество результатов.

Затем, чтобы сделать это в коде, вам нужно следовать примеру MDQueryRef.Поток кода идентичен компоненту Какао, и я считаю, что запросы гораздо проще создавать и понимать.Вы можете установить обратные вызовы какао для MDQuery - так что он довольно хорошо совместим с NSMetadataquery.

NSMetadataQuery содержит некоторые вещи iCloud, которые, я не думаю, есть в MDQuery.Так что они не идентичны, я думаю.

0 голосов
/ 28 октября 2011

Попробуйте:

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

У меня работает.

...