C# 字符串是否存在检查20k次

C# 字符串是否存在检查20k次,c#,string,search,C#,String,Search,我有一个ITunes库XML文件备份文件-大约15MB 我的C盘上有20K个音乐文件,E盘上有25K个文件,文件夹结构完全相同 我正在遍历第一个位置,逐个文件,并检查文件是否存在于第二个位置。那部分对我有用 现在,对于所有这些重复文件,如果XML中存在E驱动器的文件路径,但XML中不存在C驱动器路径,那么我想从C驱动器中删除该文件 检查XML文件中是否存在字符串的最佳方法是什么(我必须至少执行20K次)?根据您是否要计算字符串出现的次数,或者如果您只是检查字符串是否存在,您的方法会略有不同。但是

我有一个ITunes库XML文件备份文件-大约15MB

我的C盘上有20K个音乐文件,E盘上有25K个文件,文件夹结构完全相同

我正在遍历第一个位置,逐个文件,并检查文件是否存在于第二个位置。那部分对我有用

现在,对于所有这些重复文件,如果XML中存在E驱动器的文件路径,但XML中不存在C驱动器路径,那么我想从C驱动器中删除该文件


检查XML文件中是否存在字符串的最佳方法是什么(我必须至少执行20K次)?

根据您是否要计算字符串出现的次数,或者如果您只是检查字符串是否存在,您的方法会略有不同。但是,这是我要考虑的两种方式:

如果您想用最少的内存执行此操作:

逐行加载文件(或者,如果XML不是这样格式化的,则使用XML解析器逐节点加载文件……我相信有XML解析器可以做到这一点)。对每个字符串的行执行搜索操作。如果正确覆盖最后一行,内存中一次最多只能有一行/节点。这样做的缺点是需要更长的时间,文件打开的时间也更长

如果您想快速完成:

将整个文件加载到内存中,不必解析它,只需搜索每个字符串

编辑


根据您的说明,我将首先收集数组中所有重复的文件名,然后使用我的第一个方法(如上)继续扫描XML文件的每一行。如果您已经在内存中存储了20K文件名,我会犹豫是否同时加载整个15MB XML。

建议:加载为文本,使用正则表达式提取所需字符串(我认为它们包含一个特定的标记),并用它们构建一个哈希列表。您可以使用列表来检查是否存在。

按字母顺序对您要匹配的字符串列表进行排序,然后构建一个索引数组,告诉您每个字符串的起始字符列表的起始位置,可能索引到第二个字符,这取决于种类的广度以及匹配是否区分大小写

使用流逐个字符读取文件以最小化内存占用,检查索引数组以查看该字符在字符串列表中的起始位置和结束位置,以便您可以拉出该字符页(如果有任何以这些字符组合开头的内容)。然后继续在页面内部进行筛选,直到剩下一个匹配项,而下一个字符将匹配项设置为0

从要匹配的字符串列表中删除该字符串,如果需要,将其放入另一个列表中。然后开始检查下一个字符的索引,并在每次没有匹配时继续这样做

该索引为您提供了一个更有效的聚合,以最小化对其进行迭代的项数

这可以为您提供两个字符的深度索引:

Dictionary<string,int> stringIndex = new Dictionary<char,int>();
for(int i = 0; i < sortedSearchStrings.Length; i++;)
{
    if (!stringIndex.Keys.Contains(sortedSearchStrings[i][0])) stringIndex[sortedSearchStrings[i][0]] = i;
    if (!stringIndex.Keys.Contains(sortedSearchStrings[i][0] + sortedSearchStrings[i][1])) stringIndex[sortedSearchStrings[i][0] + sortedSearchStrings[i][1]] = i;
}

从XML中读取每个字符串,并将它们写入
哈希集
。如果要查找字符串,请在哈希集中查找它。读取XML的成本是O(n),对哈希集进行n次查找的成本是O(n)。不要尝试在XML中重复搜索(而是在哈希集中进行20000次搜索),因为XML没有索引/优化以进行搜索。

是否可以直接从XML文档中搜索并跳过第一步

如果是这样,您可以使用Xml.XmlDocument,然后使用Xml.XmlNode.SelectNodes(字符串),使用xpath导航文档。我不知道文档中存在什么类型的信息,但您对第二阶段的措辞方式表明,有时C:\上的路径和E:\上的路径都存在?如果是这样的话,只需检查两个IO.File.Exists,然后检查一个IO.File.Delete()

我的意思是,与其在XML文档中搜索N次字符串,不如在文档中搜索并删除重复项,以便只在文档中运行一次


不过,我不使用iTunes,也没有现成的库备份来判断它是否可以工作。

这里有一个使用Linq的简单解决方案。运行速度足够快,可一次性使用:

using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

class ITunesChecker
{
    static void Main(string[] args)
    {
        // retrieve file names
        string baseFolder = @"E:\My Music\";
        string[] filesM4a = Directory.GetFiles(baseFolder, "*.m4a", SearchOption.AllDirectories);
        string[] filesMp3 = Directory.GetFiles(baseFolder, "*.mp3", SearchOption.AllDirectories);
        string[] files = new string[filesM4a.Length + filesMp3.Length];
        Array.Copy(filesM4a, 0, files, 0, filesM4a.Length);
        Array.Copy(filesMp3, 0, files, filesM4a.Length, filesMp3.Length);

        // convert to the format used by iTunes
        for (int i = 0; i < files.Length; i++)
        {
            Uri uri = null;
            if (Uri.TryCreate(files[i], UriKind.Absolute, out uri))
            {
                files[i] = uri.AbsoluteUri.Replace("file:///", "file://localhost/");
            }
        }

        // read the files from iTunes library.xml
        XDocument library = XDocument.Load(@"E:\My Music\iTunes\iTunes Music Library.xml");
        var q = from node in library.Document.Descendants("string")
                where node.ElementsBeforeSelf("key").Where(n => n.Parent == node.Parent).Last().Value == "Location"
                select node.Value;

        // do the set operations you are interested in
        var missingInLibrary = files.Except(q, StringComparer.InvariantCultureIgnoreCase);
        var missingInFileSystem = q.Except(files, StringComparer.InvariantCultureIgnoreCase);
        var presentInBoth = files.Intersect(q, StringComparer.InvariantCultureIgnoreCase);
    }
}
使用系统;
使用System.IO;
使用System.Linq;
使用System.Xml.Linq;
类ITunesChecker
{
静态void Main(字符串[]参数)
{
//检索文件名
string baseFolder=@“E:\My Music\”;
字符串[]filesM4a=Directory.GetFiles(baseFolder,*.m4a),SearchOption.AllDirectories);
字符串[]filesm3=Directory.GetFiles(baseFolder,*.mp3),SearchOption.AllDirectories);
string[]files=新字符串[filesM4a.Length+filesm3.Length];
复制(filesM4a,0,files,0,filesM4a.Length);
复制(filesm3,0,files,filesM4a.Length,filesm3.Length);
//转换为iTunes使用的格式
for(int i=0;in.Parent==node.Parent.Last().Value==Location”
选择节点值;
//进行您感兴趣的集合操作
var missingInLibrary=files.Except(q,StringComparer.InvariantCultureInogoreCase);
var missingInFileSystem=q.Except(文件,StringComparer.InvariantCultureI
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;

class ITunesChecker
{
    static void Main(string[] args)
    {
        // retrieve file names
        string baseFolder = @"E:\My Music\";
        string[] filesM4a = Directory.GetFiles(baseFolder, "*.m4a", SearchOption.AllDirectories);
        string[] filesMp3 = Directory.GetFiles(baseFolder, "*.mp3", SearchOption.AllDirectories);
        string[] files = new string[filesM4a.Length + filesMp3.Length];
        Array.Copy(filesM4a, 0, files, 0, filesM4a.Length);
        Array.Copy(filesMp3, 0, files, filesM4a.Length, filesMp3.Length);

        // convert to the format used by iTunes
        for (int i = 0; i < files.Length; i++)
        {
            Uri uri = null;
            if (Uri.TryCreate(files[i], UriKind.Absolute, out uri))
            {
                files[i] = uri.AbsoluteUri.Replace("file:///", "file://localhost/");
            }
        }

        // read the files from iTunes library.xml
        XDocument library = XDocument.Load(@"E:\My Music\iTunes\iTunes Music Library.xml");
        var q = from node in library.Document.Descendants("string")
                where node.ElementsBeforeSelf("key").Where(n => n.Parent == node.Parent).Last().Value == "Location"
                select node.Value;

        // do the set operations you are interested in
        var missingInLibrary = files.Except(q, StringComparer.InvariantCultureIgnoreCase);
        var missingInFileSystem = q.Except(files, StringComparer.InvariantCultureIgnoreCase);
        var presentInBoth = files.Intersect(q, StringComparer.InvariantCultureIgnoreCase);
    }
}