WinRT and Windows Property System part 2: searching for files by metadata

October 24, 2011
C# File System metadata Windows 8 WinRT
 

The functions provided by WinRT to store and read files metadata are useful when you want to help your users with the files categorization. But what is even more interesting, you can use the saved properties to search for files.

For example, you can use the following code to get all the photos taken using Pentax camera and saved as .jpg files into the Pictures library:

var queryOptions = new QueryOptions(CommonFileQuery.DefaultQuery, new[] { ".jpg" });
queryOptions.FolderDepth = FolderDepth.Deep;
queryOptions.ApplicationSearchFilter = "cameramake:pentax";

StorageFileQueryResult query = 
          KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);

IReadOnlyList files = await query.GetFilesAsync();
foreach (var file in files)
{
   Debug.WriteLine(file.FileName);
}

ApplicationSearchFilter is an Advanced Query Syntax string and is optional. If it is not defined the query will simply return all .jpg files.

The first parameter in the QueryOptions constructor defines type of the query. Using this parameter you can control the search depth and the sorting method. CommonFileQuery.DefaultQuery means shallow search – the query engine will not search for the files in the subfolders of the target folder. This behavior can be altered by assigning FolderDepth.Deep value to QueryOptions.FolderDepth property.

All the ordered queries (OrderByTitle, OrderByDate, etc.) use the deep search by default and return the flat list of all the matched files or folders in all the subfolders. But what is equally important, these queries use different methods for retrieving the results. Let’s see the following queries:

var queryOptions = new QueryOptions(CommonFileQuery.DefaultQuery, new[] { ".jpg" });
queryOptions.FolderDepth = FolderDepth.Deep;
var query = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);
IReadOnlyList files = await query.GetFilesAsync();
var queryOptions = new QueryOptions(CommonFileQuery.OrderByDate, new[] { ".jpg" });
var query = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);
IReadOnlyList files = await query.GetFilesAsync();

In theory, both queries should return the same number of the files. But when I tested this code on my system, the first query returned 24 files and the second – just 3 files.

This happened because all the ordered queries use index database to search for the files while the default query inspects the file system to find the matches. On my system the index was somehow corrupted and the query was not able to get all the files. Rebuilding the index solved the issue – both queries returned the same number of files.

Using the index database for the search helps to reduce search time and resources usage – even such a simple query was 1.5 times faster in the indexed mode - but it might be a good idea to use the default mode for the critical queries, to be sure that you received a complete view.

It is very likely that the StorageFile objects returned by the queries will be used to extract metadata and generate thumbnail for presenting to the user. As this scenario is very common, WinRT provides a class that combines all these actions together:

var queryOptions = new QueryOptions(CommonFileQuery.OrderByDate, new[] { ".jpg" });
var query = KnownFolders.PicturesLibrary.CreateFileQueryWithOptions(queryOptions);

var fileInfoFactory = new FileInformationFactory(query, ThumbnailMode.PicturesView);
IReadOnlyList fileInfoList = await fileInfoFactory.GetFilesAsync();
            
foreach (FileInformation fileInfo in fileInfoList)
{
   Debug.WriteLine(fileInfo.FileName);

   ImageProperties properties = fileInfo.ImageProperties;
   properties.Keywords.Add("new");
   await properties.SavePropertiesAsync();
}

FileInformation class implements IStorageItem and IStorageFile interfaces and therefore can be used to read and write, copy or delete the file. Additionally it implements IStorageItemInformation to synchronously provide file’s thumbnail and properties.

Nothing comes for free – FileInformationFactory queries are about 3 times slower that the simple indexed queries executed with the same options. The additional time is required to extract the properties and create the thumbnails – so if you don’t need all these information, the simple query will be a better option.

blog comments powered by Disqus