【问题标题】:What is the fastest way to get lists of files and search through file lists repeatedly?获取文件列表和重复搜索文件列表的最快方法是什么?
【发布时间】:2011-12-30 11:38:56
【问题描述】:

获取文件列表和反复搜索文件列表最快的方法是什么?

情况:

  1. 一个网络驱动器上可以有 5,000 到 35,000 个文件分布在 3 到 5 个根目录(包含许多子目录)中。
  2. 用户可能会或可能不会搜索三种文件类型(tif、sus、img)。某些文件类型可以有 2-3 个不同的文件扩展名。
  3. 从文件列表(在各种数据库表中),我需要找出每个文件是否存在,如果存在,则仅将路径和文件名保存到表中。
  4. 对文件名的搜索必须区分大小写,但在保存表的路径时最好保持原来的大小写。

环境:

Windows PC 上的 C# 和 .NET 4.0。

这是最快的方法吗?:

以 FileName 作为键(小写)和 Path 作为值(原始大小写)是使用字典的最快方法吗? 这样我在搜索文件名时可以同时获得索引/路径吗?填充列表时,文件名和路径在前面被拆分。

if (d.TryGetValue("key", out value))
{
    // Log "key" and value to table  // only does one lookup
}

注意:我有点担心每个 FileType 可能会有重复的键值。 何时/如果我遇到这种情况,我应该使用哪种类型的列表和访问方法?

也许在这些罕见的情况下,我应该填充另一个重复键的列表。因为我至少需要执行以下操作之一:记录/复制/删除任何路径中的文件。

【问题讨论】:

  • 我可能会创建一个带有“FullFilePath”和“FileName”/“Path”吸气剂的对象,这些吸气剂从路径中提取这些细节。然后,创建可以迭代的那些对象的集合。 ——但这只是我。
  • @BradChristie 那么...FileInfo 类,然后呢?
  • @SpikeX:我想过,但 FileInfo 可能对于元数据来说太重了。这取决于你想要表现什么。我几乎认为在 easily-searchable collection 中设置了一个愚蠢的结构
  • @BradChristie 但这就是 FileInfo 对象的全部内容,是元数据。它根本不存储文件的内容。它们被设计为非常轻量和快速,我已经使用 FileInfo 类处理了 数十万 个文件并且没有任何问题。 -- 不要重新发明轮子。 ;)

标签: c# dictionary


【解决方案1】:

我会使用 Dictionary<string,string> 并将 FullName (path+file+ext) 更改为小写作为键,并将 FullName 更改为值。然后使用System.IO.Path 类的静态方法GetDirectoryNameGetFileName 拆分所需的部分,然后再将它们插入表中。

编辑DirectoryInfo 类的GetFiles 方法返回一个FileInfo 数组。 FileInfo 有一个 FullName 属性返回路径+文件+ext。如果内存消耗不是问题,您也可以将此FileInfo 作为值存储在字典中。 FileInfo 有一个 DirectoryName 和一个 Name 属性返回您需要的两个部分。

编辑:这是我实现的多图,它执行Directory<TKey,List<TValue>> 的东西:

/// <summary>
/// Represents a collection of keys and values. Multiple values can have the same key.
/// </summary>
/// <typeparam name="TKey">Type of the keys.</typeparam>
/// <typeparam name="TValue">Type of the values.</typeparam>
public class MultiMap<TKey, TValue> : Dictionary<TKey, List<TValue>>
{

    public MultiMap()
        : base()
    {
    }

    public MultiMap(int capacity)
        : base(capacity)
    {
    }

    /// <summary>
    /// Adds an element with the specified key and value into the MultiMap. 
    /// </summary>
    /// <param name="key">The key of the element to add.</param>
    /// <param name="value">The value of the element to add.</param>
    public void Add(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            valueList.Add(value);
        } else {
            valueList = new List<TValue>();
            valueList.Add(value);
            Add(key, valueList);
        }
    }

    /// <summary>
    /// Removes first occurence of a element with a specified key and value.
    /// </summary>
    /// <param name="key">The key of the element to remove.</param>
    /// <param name="value">The value of the element to remove.</param>
    /// <returns>true if the a element is removed; false if the key or the value were not found.</returns>
    public bool Remove(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            if (valueList.Remove(value)) {
                if (valueList.Count == 0) {
                    Remove(key);
                }
                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// Removes all occurences of elements with a specified key and value.
    /// </summary>
    /// <param name="key">The key of the elements to remove.</param>
    /// <param name="value">The value of the elements to remove.</param>
    /// <returns>Number of elements removed.</returns>
    public int RemoveAll(TKey key, TValue value)
    {
        List<TValue> valueList;
        int n = 0;

        if (TryGetValue(key, out valueList)) {
            while (valueList.Remove(value)) {
                n++;
            }
            if (valueList.Count == 0) {
                Remove(key);
            }
        }
        return n;
    }

    /// <summary>
    /// Gets the total number of values contained in the MultiMap.
    /// </summary>
    public int CountAll
    {
        get
        {
            int n = 0;

            foreach (List<TValue> valueList in Values) {
                n += valueList.Count;
            }
            return n;
        }
    }

    /// <summary>
    /// Determines whether the MultiMap contains a element with a specific key / value pair.
    /// </summary>
    /// <param name="key">Key of the element to search for.</param>
    /// <param name="value">Value of the element to search for.</param>
    /// <returns>true if the element was found; otherwise false.</returns>
    public bool Contains(TKey key, TValue value)
    {
        List<TValue> valueList;

        if (TryGetValue(key, out valueList)) {
            return valueList.Contains(value);
        }
        return false;
    }

    /// <summary>
    /// Determines whether the MultiMap contains a element with a specific value.
    /// </summary>
    /// <param name="value">Value of the element to search for.</param>
    /// <returns>true if the element was found; otherwise false.</returns>
    public bool Contains(TValue value)
    {
        foreach (List<TValue> valueList in Values) {
            if (valueList.Contains(value)) {
                return true;
            }
        }
        return false;
    }

}

【讨论】:

  • 当我搜索文件时,我只有数据库表中的文件名。那么关键不应该只是文件名吗?由于性能真的很重要,我宁愿匹配整个字符串。对吗?
  • 所以你只知道文件名,但不知道它在哪个目录?然后您可以使用Directory&lt;string,List&lt;string&gt;&gt;Directory&lt;string,List&lt;FileInfo&gt;&gt; 来存储相同文件名的多个文件信息。
  • 我猜(不确定),但由于重复很少见,我认为每个 FileType 有 2 个列表更快。普通列表 = Dictonary>。但是对于每一个积极的匹配,我都必须检查另一个列表。嗯
  • 拥有 2 个字典很复杂,并且可能不会明显更快(如果有的话)。使用我的MultiMap 实现很容易并且足够快(请参阅我的编辑)。请注意,TryGetValue 返回的是 List&lt;TValue&gt; 而不是 TValue
  • 谢谢!今天/明天会试试这个,然后回复你。
【解决方案2】:

我可能会使用文件名小写的字典作为键。价值将是一个具有所需额外信息的类。我也会像你的例子一样搜索它。如果这很慢,我可能还会尝试使用 linq 进行搜索,看看它是否更快。然而,这是这里的一个问题。这要求通过所有文件夹的所有文件都是唯一命名的。这可能是你的情况,但如果你还没有考虑过它也可能是一个问题;)

请记住,如果内存字典/列表可能发生变化,您还可以使用 FileWatcher 对象来保持与磁盘内容同步。如果它是静态的,我可能会将其全部存储在数据库表中并搜索它,然后您的程序的启动将是非静态的。

编辑: 刚才注意到您对重复的关注。如果这是一个问题,我会创建一个列表,其中 fileclass 是一个包含文件所需信息的类。然后使用 linq 搜索列表,因为这可能会给你零个、一个或多个命中。我认为这比以列表为值的字典更有效,其中列表将包含一个或多个项目(重复项)。

【讨论】:

  • 您对增加 LINQ 的开销以提高速度有何看法? (只是好奇)
  • 文件确实是静态的 - 不需要 FileWatcher。
  • 我已经考虑过重复键,并认为最快的解决方案可能是另一个字典重复列表。我使用的数据库是 MS Access 2007,所以我认为字典列表比搜索这个 Db 表要快得多。我真的需要上课吗?我只需要存储文件名、路径。出于我的简单目的,您认为 List 的想法会比 2 个字典更快吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
相关资源
最近更新 更多