【问题标题】:C# File and Directory iteration, possible to do both at one?C#文件和目录迭代,可以同时做吗?
【发布时间】:2012-03-28 18:14:25
【问题描述】:

这可能是一个令人困惑的问题,但我在目录爬虫下面写了,它将从根爬虫开始,查找所有唯一目录,然后查找所有文件并计算它们并添加它们的文件大小。但是,我编写它的方式需要访问目录两次,一次是查找目录,下一次是计算文件。如果/如何一次获取所有信息?

       Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        HashSet<string> DirectoryHolding = new HashSet<string>();
        DirectoryHolding.Add(rootDirectory);


        #region All Directory Region
        int DirectoryCount = 0;
        int DirectoryHop = 0;
        bool FindAllDirectoriesbool = true;
        while (FindAllDirectoriesbool == true)
        {
            string[] DirectoryHolder = Directory.GetDirectories(rootDirectory);
            if (DirectoryHolder.Length == 0)
            {
                if (DirectoryHop >= DirectoryHolding.Count())
                {
                    FindAllDirectoriesbool = false;
                }
                else
                {
                    rootDirectory = DirectoryHolding.ElementAt(DirectoryHop);
                }
                DirectoryHop++;
            }
            else
            {
                foreach (string DH in DirectoryHolder)
                {
                    DirectoryHolding.Add(DH);
                }
                if (DirectoryHop > DirectoryHolding.Count())
                {
                    FindAllDirectoriesbool = false;
                }
                rootDirectory = DirectoryHolding.ElementAt(DirectoryHop);
                DirectoryHop++;

            }

        }
        DirectoryCount = DirectoryHop - 2;
        #endregion



        #region File Count and Size Region
        int FileCount = 0;
        long FileSize = 0;
        for (int i = 0; i < DirectoryHolding.Count ; i++)
        {
            string[] DirectoryInfo = Directory.GetFiles(DirectoryHolding.ElementAt(i));
            for (int fi = 0; fi < DirectoryInfo.Length; fi++)
            {
                try
                {
                    FileInfo fInfo = new FileInfo(DirectoryInfo[fi]);
                    FileCount++;
                    FileSize = FileSize + fInfo.Length;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message.ToString());
                }
            }
        }

秒表结果是 1.38

int FileCount = 0;
        long FileSize = 0;
        for (int i = 0; i < DirectoryHolding.Count; i++)
        {
            var entries = new DirectoryInfo(DirectoryHolding.ElementAt(i)).EnumerateFileSystemInfos();
            foreach (var entry in entries)
            {
                if ((entry.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    DirectoryHolding.Add(entry.FullName);
                }
                else
                {
                    FileCount++;
                    FileSize = FileSize + new FileInfo(entry.FullName).Length;
                }
            }
        }

此方法的秒表是 2.01,

这对我来说毫无意义。

 DirectoryInfo Dinfo = new DirectoryInfo(rootDirectory);
            DirectoryInfo[] directories = Dinfo.GetDirectories("*.*", SearchOption.AllDirectories);
            FileInfo[] finfo = Dinfo.GetFiles("*.*", SearchOption.AllDirectories);
            foreach (FileInfo f in finfo)
            {
                FileSize = FileSize + f.Length;
            }
            FileCount = finfo.Length;
            DirectoryCount = directories.Length; 

.26 秒我认为这是赢家

【问题讨论】:

  • 提示:您不需要这样做:if (FindAllDirectoriesbool == true) 这将正常工作:if (FindAllDirectoriesbool)
  • 使用Directory.EnumerateFiles 或递归。
  • @M.Babcock 这将如何加快速度,这当然不是 foreach 循环,但速度不一样吗?我认为这里的网络连接是瓶颈,而不是代码
  • @M.Babcock 我仍然需要执行 GetDirectories 才能知道下一个目录是什么

标签: c# directoryinfo


【解决方案1】:

你可以使用Directory.EnumerateFileSystemEntries():

var entries = Directory.EnumerateFileSystemEntries(rootDirectory);
foreach (var entry in entries)
{
    if(File.Exists(entry))
    {
        //file
    }
    else
    {
        //directory
    }
}

或者DirectoryInfo.EnumerateFileSystemInfos()(这可能更高效,因为FileSystemInfo 已经拥有您需要的大部分信息,您可以跳过File.Exists 检查):

var entries = new DirectoryInfo(rootDirectory).EnumerateFileSystemInfos();
foreach (var entry in entries)
{
    if ((entry.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
    {
        //direcotry
    }
    else
    {
        //file
    }
}

【讨论】:

  • 我当然可以在这里修改代码,但是如何改变仍然找到并坐在所有目录然后返回这些目录的问题?不要试图粗鲁,我只是不明白,我必须先找到所有“条目”,然后才能找到它们
  • 信不信由你,该方法比我上面提到的两个方法慢 30%,发布的方法:stopwatch.Elapsed.TotalMinutes= 1.35 方法:= stopwatch.Elapsed.TotalMinutes 1.88跨度>
  • else语句中如何获取文件大小?
  • 我测试了第二种方法,如果我必须使用 FileInfo 大约需要 1.7 是我不必使用 fileInfo 需要 10 秒,所以如果我可以在不再次调用 fileinfo 的情况下获得文件大小,那就太棒了
  • 您必须手动获取它 - 更准确的信息,但可能比通过 DirectoryInfo.GetFiles 慢(无法击败缓存信息):long fileSize = new FileInfo(entry.Name).Length;
【解决方案2】:

通常的做法是编写递归方法。这是伪代码:

void ProcessDirectory(Dir directory)
{
    foreach (var file in directory.Files)
        ProcessFile(file);

    foreach (var child in directory.Subdirectories)
        ProcessDirectory(directory);
}

您还可以颠倒 foreach 循环的顺序。例如,要使用递归方法计算所有文件的总大小,您可以这样做:

int GetTotalFileSize(Dir directory)
{
    ulong result = 0UL;

    foreach (var child in directory.Subdirectories)
        result += GetTotalFileSize(directory);

    foreach (var file in directory.Files)
        result += file.Length;

    return result;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2020-05-02
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    相关资源
    最近更新 更多