快速检查文件名中文件是否存在的方法

时间:2012-10-17 07:53:42

标签: c# .net search directory directorysearcher

我有一个物理目录结构:

根目录(X) - >侧根中的许多子目录(1,2,3,4 ..) - >在每个子目录中存在许多文件。

Photos(Root)    
            ----        
               123456789(Child One)
                 ----
                     1234567891_w.jpg (Child two)
                     1234567891_w1.jpg(Child two)
                     1234567891_w2.jpg(Child two)
                     1234567892_w.jpg (Child two)
                     1234567892_w1.jpg(Child two)
                     1234567892_w2.jpg(Child two)
                     1234567893_w.jpg(Child two)
                     1234567893_w1.jpg(Child two)
                     1234567893_w2.jpg(Child two)
                     -----Cont      
              232344343(Child One)      
              323233434(Child One)      
              232323242(Child One)      
              232324242(Child One)      
              ----Cont..

在数据库中,我有一个表有大量名称类型为“1234567891_w.jpg”的表。

注意:数据库中的数据数量和照片数量均为lacs。

我需要一种有效且更快捷的方法来检查数据库表中每个名称是否存在于物理目录结构中。

  • 例如:在照片(根)内的物理文件夹中是否存在任何带有“1234567891_w.jpg”名称的文件。*

如果我错过了这里提供的任何信息,请告诉我。

更新:

我知道如何在目录中找到存在的文件名。但我正在寻找一种有效的方法,因为在超过40 GB的数据中检查每个文件名(来自记录的lacs)将耗费太多资源。

4 个答案:

答案 0 :(得分:2)

您可以尝试根据数据库所在的目录对数据库进行分组。以某种方式对它们进行排序(例如,基于文件名),然后获取该目录中的文件数组 string[] filePaths = Directory.GetFiles(@"c:\MyDir\");。现在你只需要比较字符串。

答案 1 :(得分:1)

如果您可以执行类似此操作的情况,那么文件似乎是唯一命名的

var fileNames = GetAllFileNamesFromDb();
var physicalFiles = Directory.GetFiles(rootDir, 
                                        string.Join(",",fileNames),
                                        SearchOptions.AllDirectories)
                                        .Select(f=>Path.GetFileName(f));
var setOfFiles = new Hashset<string>(physicalFiles);
var notPresent = from name in fileNames
                 where setOfFiles.Contains(name)
                 select name;
  • 首先从datatbase获取文件的所有名称
  • 然后从根目录搜索所有文件并包括所有子目录以获取所有物理文件
  • 创建用于快速查找的哈希集
  • 然后将fileNames与集合中的那些匹配。

Hashset基本上只是一个集合。这是一个只能包含一次项目的集合(即没有重复项)Hashset中的相等性基于HashCode,并且用于确定项目是否在集合中的查找是O(1)。

这种方法要求你在内存中存储一​​个可能很大的Hashset,并且根据它的大小,它可能会影响系统到一个扩展,它不再优化应用程序的速度,而是传递最佳值。

与大多数优化一样,它们都是折衷方案,关键是在应用程序为最终用户生成的价值环境中找到所有权衡之间的平衡

答案 2 :(得分:1)

这可能听起来很有趣,或者我可能不清楚或者没有提供太多信息。

但是从目录模式我得到了一个很好的方法来处理它:

AS文件名存在的概率仅在一个位置,即:

<强>根/子目录/文件名

我应该使用:

File.Exists(根/子目录/文件名);

即 - 照片/ 123456789 / 1234567891_w.jpg

我认为这将是 O(1)

答案 3 :(得分:0)

不幸的是,它们不是可以用来提高性能的灵丹妙药。一如既往,它将在速度和记忆之间进行权衡。他们的两个方面也可能缺乏性能:数据库站点和硬盘驱动器i / o速度。

因此,为了提高速度,我将在第一步中提高数据库查询的性能,以确保它可以足够快地返回名称以进行搜索。因此,请确保您的查询速度快,也可能使用{im SQL SQL案例}关键字,例如READ SEQUENTIAL,在这种情况下,您将在查询仍在运行时检索第一个结果,而您不必等到查询完成后,将名称作为一个大块。

在另一个硬盘方面你可以调用Directory.GetFiles(),但是这个调用会阻塞,直到它迭代所有文件并返回一个包含所有文件名的大数组。这将是内存消耗路径,并且需要一段时间才能进行第一次搜索,但如果您之后只在该阵列上工作,则可以获得所有连续搜索的速度提升。另一种方法是调用Directory.EnumerateFiles(),它可以在每次调用时动态搜索驱动器,因此可能获得第一次搜索的速度,但是它们不会发生任何内存存储以用于下一次搜索,这会改善内存占用但是成本速度,因为他们的内存中没有可以搜索的数组。另一方面,如果检测到您反复遍历相同的文件并且某些缓存发生在较低级别,操作系统也会执行一些缓存。

因此,对于hdd网站上的检查使用Directory.GetFiles()如果返回的数组不会破坏您的内存并对此进行所有搜索(可能将其放入HashSet以进一步提高性能,如果文件名only或full path取决于你从数据库中获得的内容),在另一种情况下使用Directory.EnumerateFiles()并希望最好的一些缓存是OS。

更新

重新阅读你的问题和评论后,据我所知,你有一个像1234567891_w.jpg这样的名字,你不知道名称的哪一部分代表了目录部分。因此,在这种情况下,您需要进行显式搜索,导致遍历所有目录只需花费很多时间。下面是一些示例代码,它可以让您了解如何在第一次拍摄中解决此问题:

string rootDir = @"D:\RootDir";

// Iterate over all files reported from the database
foreach (var filename in databaseResults)
{
    var fullPath = Path.Combine(rootDir, filename);

    // Check if the file exists within the root directory
    if (File.Exists(Path.Combine(rootDir, filename)))
    {
        // Report that the file exists.
        DoFileFound(fullPath);
        // Fast exit to continue with next file.
        continue;
    }

    var directoryFound = false;

    // Use the filename as a directory
    var directoryCandidate = Path.GetFileNameWithoutExtension(filename);
    fullPath = Path.Combine(rootDir, directoryCandidate);

    do
    {
        // Check if a directory with the given name exists
        if (Directory.Exists(fullPath))
        {
            // Check if the filename within this directory exists
            if (File.Exists(Path.Combine(fullPath, filename)))
            {
                // Report that the file exists.
                DoFileFound(fullPath);
                directoryFound = true;
            }

            // Fast exit, cause we looked into the directory.
            break;
        }

        // Is it possible that a shorter directory name
        // exists where this file exists??
        // If yes, we have to continue the search ...
        // (Alternative code to the above one)
        ////// Check if a directory with the given name exists
        ////if (Directory.Exists(fullPath))
        ////{
        ////    // Check if the filename within this directory exists
        ////    if (File.Exists(Path.Combine(fullPath, filename)))
        ////    {
        ////        // Report that the file exists.
        ////        DoFileFound(fullPath);

        ////        // Fast exit, cause we found the file.
        ////        directoryFound = true;
        ////        break;
        ////    }
        ////}

        // Shorten the directory name for the next candidate
        directoryCandidate = directoryCandidate.Substring(0, directoryCandidate.Length - 1);
    } while (!directoryFound
              && !String.IsNullOrEmpty(directoryCandidate));

    // We did our best but we found nothing.
    if (!directoryFound)
        DoFileNotAvailable(filename);
}

我能想到的唯一一点性能提升,就是将找到的目录放到HashSet中,然后在用Directory.Exists()检查之前使用它来检查现有目录,但也许这不会获得任何东西,因为操作系统已经在目录查找中进行了一些缓存,然后几乎与本地缓存一样快。但是对于这些事情,你只需要测量你的具体问题。