媒体搜索应用介绍

在数字时代,经常需要从大量的媒体文件中快速找到特定的文件。无论是照片、音乐还是视频,一个有效的搜索工具可以大大提高工作效率。本文将介绍一个名为“My Media Search”的Windows应用程序,它可以帮助用户快速索引和搜索指定目录下的媒体文件。

My Media Search是一个基于Windows Forms的应用程序,它使用.NET Framework 4.7.2进行开发。虽然开发者原本希望使用.NET 5.0,但由于获取文件属性和缩略图的现成代码主要来自Windows API,特别是Microsoft.WindowsAPICodePack库,因此最终选择了.NET Framework。

该应用程序的核心是metastrings数据库。开发者对metastrings进行了重新设计,以适应这个应用程序的需要,并提高了其整体的软件一致性。例如,放弃了对MySQL的支持,因为SQLite没有字符串长度限制,这使得开发者可以移除“长字符串”API的限制。

为了简化数据库的使用,开发者为metastrings添加了对所有字符串值的全文索引功能。这使得metastrings非常适合为应用程序添加轻量级的数据库支持,而不需要支持复杂的客户端-服务器数据库解决方案。

代码概览

lib项目包含了SearchInfo类,它实现了大部分非用户界面的功能。cmd项目是SearchInfo的原型,可以用来索引任意目录、更新索引和执行搜索。需要注意的是,它只索引给它的目录,并删除任何其他目录的索引。这只是一个概念验证。

以下是cmd项目中Main函数的代码示例:

using System; using System.Threading.Tasks; using System.Collections.Generic; using System.IO; namespace fql { class Program { [STAThread] static async Task Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Usage: "); return 0; } string dirPath = args[0].Trim(); if (!Directory.Exists(dirPath)) { Console.WriteLine("ERROR: Directory does not exist: {0}", dirPath); return 1; } while (true) { Console.WriteLine(); Console.WriteLine("Commands: reset, update, search, quit"); Console.Write("> "); string line = Console.ReadLine().Trim(); if (string.IsNullOrEmpty(line)) continue; if (line == "reset") { SearchInfo.Reset(); Console.WriteLine("DB reset"); } else if (line == "update") { var updateResult = await SearchInfo.UpdateAsync(new List { dirPath }, new List(), OnDirectoryUpdate); Console.WriteLine("DB updated: files added: {0} - removed: {1} - modified: {2} - indexed: {3}", updateResult.filesAdded, updateResult.filesRemoved, updateResult.filesModified, updateResult.indexSize); } else if (line.StartsWith("search ")) { var results = await SearchInfo.SearchAsync(line.Substring("search ".Length).Trim()); Console.WriteLine("Search results: {results.Count}"); foreach (var result in results) Console.WriteLine(result); } else if (line == "quit") { Console.WriteLine("Quitting..."); break; } } Console.WriteLine("All done."); return 0; } static void OnDirectoryUpdate(UpdateInfo update) { Console.WriteLine(update.ToString()); } } }

app项目是顶级的Windows Forms应用程序,它包含了标准的Windows Forms元素。

SearchInfo类

SearchInfo类提供了获取文件元数据的功能。以下是GetFileMetadata函数的代码示例:

public static Dictionary GetFileMetadata(string filePath) { Dictionary metadata = new Dictionary(); Shell32.Shell shell = new Shell32.Shell(); Shell32.Folder objFolder = shell.NameSpace(Path.GetDirectoryName(filePath)); List headers = new List(); for (int i = 0; i < short.MaxValue; ++i) { string header = objFolder.GetDetailsOf(null, i); if (string.IsNullOrEmpty(header)) break; headers.Add(header); } if (headers.Count == 0) return metadata; foreach (Shell32.FolderItem2 item in objFolder.Items()) { if (!filePath.Equals(item.Path, StringComparison.OrdinalIgnoreCase)) continue; for (int i = 0; i < headers.Count; ++i) { string details = objFolder.GetDetailsOf(item, i); if (!string.IsNullOrWhiteSpace(details)) metadata.Add(headers[i], details); } } return metadata; }

GetFileMetadata函数是使用.NET Framework而不是.NET 5+的一个要求。没有这个函数和搜索结果的平铺视图,.NET 5+可能会起作用。

搜索索引算法

搜索索引算法的步骤如下:

  • 收集选定目录下的所有文件系统文件路径和最后修改日期。
  • 移除排除目录中的所有文件系统文件路径。
  • 收集数据库中所有文件路径和最后修改日期。
  • ProcessFiles函数:遍历所有文件路径(文件系统和数据库),确定哪些需要添加或从数据库中移除。
  • 执行数据库操作以更新索引。

以下是ProcessFiles函数的实现:

private static void ProcessFiles(IEnumerable filePaths, DirProcessInfo info) { List filesToAdd = new List(); List filesToRemove = new List(); foreach (string filePath in filePaths) { bool inDb = info.filesLastModifiedInDb.ContainsKey(filePath); bool inFs = info.filesLastModifiedInFs.ContainsKey(filePath); if (inDb && !inFs) { ++info.filesRemoved; filesToRemove.Add(filePath); continue; } if (inFs && !inDb) { ++info.filesAdded; filesToAdd.Add(filePath); continue; } if (!inDb && !inFs) { ++info.filesRemoved; filesToRemove.Add(filePath); continue; } if (info.filesLastModifiedInDb[filePath] < info.filesLastModifiedInFs[filePath]) { ++info.filesModified; filesToAdd.Add(filePath); continue; } } info.toDelete = filesToRemove; info.toAdd = new List>(filesToAdd.Count); foreach (string filePath in filesToAdd) { string searchData = filePath.Substring(UserRoot.Length).Replace(Path.DirectorySeparatorChar, '\'').Replace('.', '\''); while (searchData.Contains(" ")) searchData = searchData.Replace(" ", " "); searchData = searchData.Trim(); long lastModified = info.filesLastModifiedInFs[filePath]; info.toAdd.Add(new Tuple(filePath, lastModified, searchData)); } }

ProcessFiles函数计算searchData字符串进行全文索引时,会分割路径组件,去掉文件扩展名,消除双空格,并修剪结果。

一旦ProcessFiles确定了需要执行的操作,这段代码就会与metastrings交互以完成操作:

using (var ctxt = msctxt.GetContext()) { update.Start("Cleaning search index...", dirProcInfo.toDelete.Count); updater?.Invoke(update); await ctxt.Cmd.DeleteAsync("files", dirProcInfo.toDelete); update.Start("Updating search index...", dirProcInfo.toAdd.Count); updater?.Invoke(update); Define define = new Define("files", null); foreach (var tuple in dirProcInfo.toAdd) { define.key = tuple.Item1; define.metadata["filelastmodified"] = tuple.Item2; define.metadata["searchdata"] = tuple.Item3; await ctxt.Cmd.DefineAsync(define); ++update.current; if ((update.current % 100) == 0) updater?.Invoke(update); } }

构建这个应用程序并享受使用它的乐趣。相信会发现它对于挖掘成千上万的图片和歌曲以找到想要的东西非常有用。

实现这个应用程序得益于metastrings的帮助。

希望现在有信心将全文搜索添加到应用程序中。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485