TheSwamp

Code Red => .NET => Topic started by: Kerry on December 19, 2008, 09:09:46 PM

Title: Findfile recursive ..
Post by: Kerry on December 19, 2008, 09:09:46 PM
FindFile in the net API is handy ... as it is in lisp ... but the limiting search folders is sometimes a restraint

... think of the case where you know the file you want is nested in a tree structure and because of dynamics you may not know the location.

This code is beta, but seems to do the job.

This is the tree I'm looking at .. the tree structure is dynamic but I know the file I want is in there somewhere.

(http://www.theswamp.org/screens/index.php?dir=KerryBrown/&file=FindFileRecursion01.png)

First try a findfile with the qualified Path

Then some recursion variations ..

Code: [Select]
        [CommandMethod("Cmd2")]
        static public void test2()
        {
            Database db = HostApplicationServices.WorkingDatabase;
            Editor ed = AcadApp.DocumentManager.MdiActiveDocument.Editor;
            string fileName = @"F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg";
     
            ed.WriteMessage("\n\n ----------- FindFile(... " );
            string qualifiedPath = HostApplicationServices.Current.
                            FindFile(fileName, db, FindFileHint.Default);
            if (string.IsNullOrEmpty(qualifiedPath))
            {
                ed.WriteMessage("\nOooops, Can't find file " + fileName);
            } else
            {
                ed.WriteMessage("\nFile Found at " + qualifiedPath);
            }
            /////
            ed.WriteMessage("\n\n ----------- FindFilesRecursive(...  " + "*.*" );
            List<string> fileList1 = FindFilesRecursive(@"F:\_kdub_testing", "*.*");
            foreach (string s in fileList1)
            {
                ed.WriteMessage("\n" + s);
            }
            /////
            ed.WriteMessage("\n\n ----------- FindFilesRecursive(...  " + "*.txt" );
            List<string> fileList2 = FindFilesRecursive(@"F:\_kdub_testing", "*.txt");
            foreach (string s in fileList2)
            {
                ed.WriteMessage("\n" + s);
            }
            /////
            ed.WriteMessage("\n\n ----------- FindFilesRecursive(...  " + "*nest*" );
            List<string> fileList3 = FindFilesRecursive(@"F:\_kdub_testing", "*nest*");
            foreach (string s in fileList3)
            {
                ed.WriteMessage("\n" + s);
            }
            /////
            ed.WriteMessage("\n\n ----------- FindFilesRecursive(...  " + "Squircle.dwg" );
            List<string> fileList4 = FindFilesRecursive(@"F:\_kdub_testing", "*Squircle.dwg");
            foreach (string s in fileList4)
            {
                ed.WriteMessage("\n" + s);
            }
            /////
            ed.WriteMessage("\n\n ----------- FindFilesRecursive(...  " + "SQUIRCLE.dwg" );
            List<string> fileList5 = FindFilesRecursive(@"F:\_kdub_testing", "SQUIRCLE.dwg");
            foreach (string s in fileList5)
            {
                ed.WriteMessage("\n" + s);
            }
            /////
        }



        static List<string> FindFilesRecursive(string initialFolder, string searchPattern)
        {         
            // declare the file results list.
            List<string> resultList = new List<string>();

            // declare dynamic stack of folders.
            Stack<string> folderStack = new Stack<string>();

            // Add initialFolder to stack.
            folderStack.Push(initialFolder);

            // while there are Folders and child-Folders on the stack ...
            while (folderStack.Count > 0)
            {               
                // remove the top Folder name from the stack and
                // see what the folder contains ....
                string dir = folderStack.Pop();
                try
                {                   
                    // Add all files for/in this folder to the result List.
                    resultList.AddRange(Directory.GetFiles(dir, searchPattern));
                   
                    // Add all sub-folders for/in this folder to the Stack.
                    foreach (string dn in Directory.GetDirectories(dir))
                    {
                        folderStack.Push(dn);
                    }
                } catch
                {                   
                    // problem opening folder
                }
            }
            return resultList;
        }   



... and the results ..

Quote
Command: netload

Command: cmd2


 ----------- FindFile(...
File Found at F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg

 ----------- FindFilesRecursive(...  *.*
F:\_kdub_testing\nest-0\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\cross.dwg
F:\_kdub_testing\nest-0\nest-03\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-035\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-035\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0342\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0342\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\squircle.txt
F:\_kdub_testing\nest-0\nest-03\nest-033\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-033\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0322\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0322\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0321\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0321\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-031\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-031\cross.dwg
F:\_kdub_testing\nest-0\nest-02\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\nest-02421\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\nest-02421\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0241\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0241\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-023\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-023\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\nest-0221\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\nest-0221\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-021\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-021\cross.dwg
F:\_kdub_testing\nest-0\nest-01\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\code .txt
F:\_kdub_testing\nest-0\nest-01\Copy nested stuff .txt
F:\_kdub_testing\nest-0\nest-01\cpuid.txt
F:\_kdub_testing\nest-0\nest-01\cross.dwg
F:\_kdub_testing\nest-0\nest-01\Shared Folder Test.txt
F:\_kdub_testing\nest-0\nest-01\nest-013\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-013\cross.dwg
F:\_kdub_testing\nest-0\nest-01\nest-012\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-012\cross.dwg
F:\_kdub_testing\nest-0\nest-01\nest-011\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-011\cross.dwg
F:\_kdub_testing\Dwgs\SECT-HEAD-1R.dwg

 ----------- FindFilesRecursive(...  *.txt
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\squircle.txt
F:\_kdub_testing\nest-0\nest-01\code .txt
F:\_kdub_testing\nest-0\nest-01\Copy nested stuff .txt
F:\_kdub_testing\nest-0\nest-01\cpuid.txt
F:\_kdub_testing\nest-0\nest-01\Shared Folder Test.txt

 ----------- FindFilesRecursive(...  *nest*
F:\_kdub_testing\nest-0\nest-01\Copy nested stuff .txt

 ----------- FindFilesRecursive(...  Squircle.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg

 ----------- FindFilesRecursive(...  SQUIRCLE.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg


Title: Re: Findfile recursive ..
Post by: Kerry on December 19, 2008, 09:38:39 PM
I 'spose I could try a LINQ Query as well ....  :|
Title: Re: Findfile recursive ..
Post by: It's Alive! on December 19, 2008, 09:51:06 PM
Nice work Kerry!  8-)
Title: Re: Findfile recursive ..
Post by: Kerry on December 19, 2008, 09:54:29 PM

Thanks Dan.

Holidays are great .. plenty of research and play time :)
Title: Re: Findfile recursive ..
Post by: TonyT on December 20, 2008, 11:52:38 PM
FindFile in the net API is handy ... as it is in lisp ... but the limiting search folders is sometimes a restraint

... think of the case where you know the file you want is nested in a tree structure and because of dynamics you may not know the location.

This code is beta, but seems to do the job.


Assuming you actually wanted a non-recursive version,
I suppose that works.

Otherwise, this (which I've been using for ages) can do it:

Code: [Select]

/// Recursive file finder
///
///    E.g:  string files[] = FindFiles.Find( "d:\\MyDrawings", "*.dwg" );
///

public static class FindFiles
{
   public static string[] Find( string folder, string pattern )
   {
      List<string> result = new List<string>();
      Find( folder, pattern, result );
      return result.ToArray();
   }

   private static void Find( string folder, string pattern, List<string> result )
   {
      result.AddRange( Directory.GetFiles( folder, pattern ) );
      foreach( string directory in Directory.GetDirectories( folder ) )
         Find( Path.Combine( folder, directory ), pattern, result );
   }
}

Title: Re: Findfile recursive ..
Post by: It's Alive! on December 21, 2008, 12:08:34 AM
Nice Tony!

I had heard a rumor that most code houses do not allow recursive functions in production code for fear of a stack overflow,
anyone know if this is true?  Obviously though, recursion is sometimes the most elegant way to solve certain tasks.  :mrgreen:
Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 12:12:22 AM

Thanks Tony, I'll have a play tonight  ..

I assume the
///    E.g:  string files[] = FindFiles.Find( "d:\\MyDrawings", "*.dwg" );
should be
///    E.g:  string[] files = FindFiles.Find( "d:\\MyDrawings", "*.dwg" );


Title: Re: Findfile recursive ..
Post by: TonyT on December 21, 2008, 02:55:42 AM
Nice Tony!

I had heard a rumor that most code houses do not allow recursive functions in production code for fear of a stack overflow,
anyone know if this is true?  Obviously though, recursion is sometimes the most elegant way to solve certain tasks.  :mrgreen:


Hi Dan.

The decision is usually linked to praticle use, e.g., if you have a folder
structure deep enough to overflow the stack in a simple case like that,
you'd be better off firing the IT management that allowed things to get
that way, and give the programmer that wrote the recursive function
that merely exposed the larger problem a raise and a promotion :lmao:

I use recursion quite a bit, but in all cases I am more than confident
it will never go deep enough to use up the stack, and I have yet to
see it happen.

Also, there are quite a few compilers that know how to optimize
properly-tail-recursive code, and output iterative code that does
the job. I don't believe that C# does it, but most LISP and Scheme
compilers do, so an unconditional mandate banning recursion with
no regards to what tools are used or whether they can optimize
tail-recusive, seems a bit silly.

Title: Re: Findfile recursive ..
Post by: uncoolperson on December 21, 2008, 12:11:08 PM
I use this (sorry I'm way too lazy today to clean this up) for this thing http://www.theswamp.org/index.php?topic=10211.0

Quote
private bool refreshstuff(string thefoldername, TreeNode ParentNode)
        {
            bool keep = false;// used to keep track of keeping the node
            try
            {
                if (count <= maxfolder)// only do this until we hit max count, otherwise stop
                {
                    count++;
                    if (checkBox1.Checked)// subdirectories too?
                    {
                        string[] folderEntries = Directory.GetDirectories(thefoldername);// get the folders in 'thefoldername'
                        foreach (string curfolder in folderEntries) // for each folder process it recursivly (yay!)
                        {
                            TreeNode NextNode = ParentNode.Nodes.Add(curfolder);
                            if (!refreshstuff(curfolder, NextNode)) // see if refreshstuff says to keep things around
                            {
                                NextNode.Remove();
                                keep = keep | false;// i don't know why this is here... but i'm keeping it around anyway (shouldn't x | false == x)
                            }
                            else
                            {
                                keep = true; // we want to keep stuff because refreshstuff said so, so remember that
                            }
                        }
                    }

                }
*Giant file filtering snip (date of last edit, user that last edited, file name pattern)*
                else if (!err && checkBox1.Checked)// if we havenn't hit and error, and we do want to check subdirectories... but we have searched alittle too much let the user know
                {
                    MessageBox.Show(Form1.ActiveForm, "too many subfolders! get more detailed", "errr", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    err = true;// and keep track of this (don't want to be bombarded with errors
                }


*some more snipage*
            return keep;// let the calling function know what was found in the directory
        } // the thinking refresh tree function (recursive fun)
Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 10:00:46 PM
and, because it's Monday and I'm home ....

a little LINQ

var InitialFolderList = new List<string> { @"F:\_kdub_testing"};
var dirQuery = InitialFolderList
   .Where(dir => Directory.Exists(dir))
   .SelectMany(dir =>
   Directory.GetFiles( dir, "*.*", SearchOption.AllDirectories) );
var filesQuery = InitialFolderList
   .Where(dir=> File.Exists(dir));
   
var SortedFileList = dirQuery.Union(filesQuery).OrderBy (s => s);

SortedFileList.Dump ("Ordered alphabetically");


Quote
F:\_kdub_testing\Dwgs\SECT-HEAD-1R.dwg
F:\_kdub_testing\nest-0\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\cross.dwg
F:\_kdub_testing\nest-0\nest-01\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\code .txt
F:\_kdub_testing\nest-0\nest-01\Copy nested stuff .txt
F:\_kdub_testing\nest-0\nest-01\cpuid.txt
F:\_kdub_testing\nest-0\nest-01\cross.dwg
F:\_kdub_testing\nest-0\nest-01\nest-011\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-011\cross.dwg
F:\_kdub_testing\nest-0\nest-01\nest-012\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-012\cross.dwg
F:\_kdub_testing\nest-0\nest-01\nest-013\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-01\nest-013\cross.dwg
F:\_kdub_testing\nest-0\nest-01\Shared Folder Test.txt
F:\_kdub_testing\nest-0\nest-02\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-021\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-021\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\nest-0221\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-022\nest-0221\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-023\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-023\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0241\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0241\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\cross.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\nest-02421\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-02\nest-024\nest-0242\nest-02421\cross.dwg
F:\_kdub_testing\nest-0\nest-03\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-031\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-031\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0321\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0321\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0322\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-032\nest-0322\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-033\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-033\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\Squircle.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0341\squircle.txt
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0342\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-034\nest-0342\cross.dwg
F:\_kdub_testing\nest-0\nest-03\nest-035\Alphabet Soup.dwg
F:\_kdub_testing\nest-0\nest-03\nest-035\cross.dwg
 
Title: Re: Findfile recursive ..
Post by: It's Alive! on December 21, 2008, 10:03:31 PM
Alphabet Soup.dwg  :laugh:
Title: Re: Findfile recursive ..
Post by: pkohut on December 21, 2008, 10:44:57 PM
and, because it's Monday and I'm home ....

Monday? What UTM are you in?  10T for me.

Paul
Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 11:00:34 PM
Gender:   yes
Age:         Mesozoic
Location:     Brisbane, Australia [ gmt +10 ]
Local Time: 2008-12-21, 14:00:45
Title: Re: Findfile recursive ..
Post by: pkohut on December 21, 2008, 11:12:46 PM
Gender:   yes
Age:         Mesozoic
Location:     Brisbane, Australia [ gmt +10 ]
Local Time: 2008-12-21, 14:00:45

Ha, not ASL, but thanks.

Seattle, WA gmt-8
20:06:00, 12-21-08
Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 11:17:03 PM
ok .. UTM is 56J
Title: Re: Findfile recursive ..
Post by: It's Alive! on December 21, 2008, 11:24:53 PM
I’m in 17T but will be in 51R in February.

It's too cold in 17T   :lol:
Title: Re: Findfile recursive ..
Post by: TonyT on December 21, 2008, 11:25:27 PM
Quote

   SearchOption.AllDirectories


From the docs: ''...follows symbolic links...', which is
microsoft-ese for 'follows shortcuts'.

IOW, when it finds a shortcut to a folder that was
already processed in a child of that folder, it will
process the parent folder again.

IOW, this option is dangerous because it can lead
to infinite recursion.

Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 11:27:29 PM
Dan,
that  sounds like really bad poetry lyrics
Title: Re: Findfile recursive ..
Post by: It's Alive! on December 21, 2008, 11:38:46 PM
WooahYa I’m down and out in 17T where the wind chill is -17°C   :laugh:
Title: Re: Findfile recursive ..
Post by: Kerry on December 21, 2008, 11:42:41 PM
Quote

   SearchOption.AllDirectories


From the docs: ''...follows symbolic links...', which is
microsoft-ese for 'follows shortcuts'.

IOW, when it finds a shortcut to a folder that was
already processed in a child of that folder, it will
process the parent folder again.

IOW, this option is dangerous because it can lead
to infinite recursion.



First Time I've read that Tony ... and the SearchOption.AllDirectories has been around for a while ... surprised it's not plastered all over the web.
Title: Re: Findfile recursive ..
Post by: TonyT on December 22, 2008, 05:29:17 AM
Actually, I think my translation of Microsoft-ese may have been
incorrect. Reparse points (like mapped drives) that can create a
circular or cyclical reference, is the problem, not shortcuts.

http://msdn.microsoft.com/en-us/library/ms143448.aspx   

(See the remarks)

The following link also has some useful information on traversing
the file system, and other potential pitfalls like directory access
rights, and so on:

http://msdn.microsoft.com/en-us/library/bb513869.aspx

As far as 'stack-o-phobia' goes :D, the depth of recursion equals
the depth of folder nesting and from my calculations, unless there
are folders nested ~250 levels deep or more, I think recursion is
a safe approach. The use of the stack can also be minimized by
using non-static methods and storing the current folder in a non
static member variable, rather than passing it as an argument to
the recursive method (which is stored in each call's stack frame).

CLR 4.0 has tail-recursion optimization, but only for F#, by way of
that compiler. From what I've read, the problem with tail-recursion
optimization in .NET is that the security model relies heavily on call
stack introspection to detect the calling context of methods (e.g.,
examine the call stack to see who is calling your method), which
can preclude optimizing tail-recursive calls into iterative loops.

One reason that purely-recursive or functional approaches with no
side-effects are desirable for solving problems like this, is that they
are better suited for parallel execution (even though in this case,
disk I/O is the likely bottleneck and limiting factor).

A stack-based approach could not easily run on mutliple CPU cores.

Quote

   SearchOption.AllDirectories


From the docs: ''...follows symbolic links...', which is
microsoft-ese for 'follows shortcuts'.

IOW, when it finds a shortcut to a folder that was
already processed in a child of that folder, it will
process the parent folder again.

IOW, this option is dangerous because it can lead
to infinite recursion.



First Time I've read that Tony ... and the SearchOption.AllDirectories has been around for a while ... surprised it's not plastered all over the web.
Title: Re: Findfile recursive ..
Post by: Draftek on December 22, 2008, 07:52:11 AM
Excellent Thread!
Thanks guys.
Title: Re: Findfile recursive ..
Post by: T.Willey on December 22, 2008, 03:29:34 PM
Couldn't you just use ' DirectoryInfo.GetFiles ' and have the search option set to ' AllDirectories '?  Untested, but I have this in my batch plot program, learned from Glenn, and it works with a filter for ' *.dwg '.

MSDN page for DirectoryInfo.GetFiles
[ http://msdn.microsoft.com/en-us/library/ms143327.aspx ]
Title: Re: Findfile recursive ..
Post by: TonyT on December 23, 2008, 09:27:04 AM
Couldn't you just use ' DirectoryInfo.GetFiles ' and have the search option set to ' AllDirectories '?  Untested, but I have this in my batch plot program, learned from Glenn, and it works with a filter for ' *.dwg '.

MSDN page for DirectoryInfo.GetFiles
[ http://msdn.microsoft.com/en-us/library/ms143327.aspx ]

Yes you can, but as mentioned on the page at the link I posted,
the entire operation fails if you don't have sufficient access rights
(as rare as that may be) for every sub directory.

If you traverse the folder tree manually, you can handle the security
exceptions that are thrown if you don't have sufficient rights for a
given folder, log the error or do whatever else you want to do, and
continue processing folders, without the entire operation failing.

Title: Re: Findfile recursive ..
Post by: T.Willey on December 23, 2008, 11:01:05 AM
Couldn't you just use ' DirectoryInfo.GetFiles ' and have the search option set to ' AllDirectories '?  Untested, but I have this in my batch plot program, learned from Glenn, and it works with a filter for ' *.dwg '.

MSDN page for DirectoryInfo.GetFiles
[ http://msdn.microsoft.com/en-us/library/ms143327.aspx ]

Yes you can, but as mentioned on the page at the link I posted,
the entire operation fails if you don't have sufficient access rights
(as rare as that may be) for every sub directory.

If you traverse the folder tree manually, you can handle the security
exceptions that are thrown if you don't have sufficient rights for a
given folder, log the error or do whatever else you want to do, and
continue processing folders, without the entire operation failing.



Thanks Tony.  When I get a chance I'll go and read the pages you linked to.
Title: Re: Findfile recursive ..
Post by: TonyT on December 23, 2008, 11:56:56 AM
And if you are only searching for files based on a pattern, it may not
matter if you have access rights, so AllDirectories may work in any
case. In my own file search class, I can do more specialized searches
that involve accessing each file (e.g., modified after a certain date,
or what have you), which means that my code must have the needed
access rights.

Couldn't you just use ' DirectoryInfo.GetFiles ' and have the search option set to ' AllDirectories '?  Untested, but I have this in my batch plot program, learned from Glenn, and it works with a filter for ' *.dwg '.

MSDN page for DirectoryInfo.GetFiles
[ http://msdn.microsoft.com/en-us/library/ms143327.aspx ]

Yes you can, but as mentioned on the page at the link I posted,
the entire operation fails if you don't have sufficient access rights
(as rare as that may be) for every sub directory.

If you traverse the folder tree manually, you can handle the security
exceptions that are thrown if you don't have sufficient rights for a
given folder, log the error or do whatever else you want to do, and
continue processing folders, without the entire operation failing.



Thanks Tony.  When I get a chance I'll go and read the pages you linked to.
Title: Re: Findfile recursive ..
Post by: gile on November 10, 2010, 05:53:50 PM
Hi,

I know this is an old topic, but while I'm trying to have a look around F#, I thaught it was a good exercice.

A 'try ... with' ( as C# 'try ... catch') statements used to ignore the limited access folders

Code: [Select]
let FindFiles folder pattern =
    let lst = ref List.Empty
    let rec foo dir pat =
        for f in Directory.GetFiles(dir, pat) do lst := f :: !lst
        for d in Directory.GetDirectories(dir) do
            try foo d pat with | ex -> ignore()
    foo folder pattern
    List.toArray(List.rev(!lst))
Title: Re: Findfile recursive ..
Post by: kaefer on November 11, 2010, 04:21:54 AM
Hi,

I know this is an old topic, but while I'm trying to have a look around F#, I thaught it was a good exercice.

A 'try ... with' ( as C# 'try ... catch') statements used to ignore the limited access folders

Code: [Select]
let FindFiles folder pattern =
    let lst = ref List.Empty
    let rec foo dir pat =
        for f in Directory.GetFiles(dir, pat) do lst := f :: !lst
        for d in Directory.GetDirectories(dir) do
            try foo d pat with | ex -> ignore()
    foo folder pattern
    List.toArray(List.rev(!lst))

Hi Gile,

welcome to the club! (Cue J.H.Marx: "I don’t care to belong to any club that will have me as a member.")

The canonical example of recursive directory search is of course here: http://www.expert-fsharp.com/CodeSamples/Chapter03/Example08/script.fsx (http://www.expert-fsharp.com/CodeSamples/Chapter03/Example08/script.fsx), from Expert F# by Don Syme, Adam Granicz and Antonio Cisternino.

Modifying that with the requirement to ignore dirs with insufficient permission and to return an array yields:
Code: [Select]
let FindFiles folder pat =
    let rec foo dir =
        try
            Directory.GetDirectories dir |> Array.collect foo
            |> Array.append (Directory.GetFiles(dir, pat))
        with _ -> Array.empty
    foo folder

Have lots of fun! Thorsten
Title: Re: Findfile recursive ..
Post by: gile on November 11, 2010, 05:17:45 AM
Thank you very much kaefer :-o
Title: Re: Findfile recursive ..
Post by: gile on November 12, 2010, 02:41:15 AM
Hi,

It seems there's no need to use a sub function:
Code: [Select]
let rec FindFiles dir pat =
    try
        Directory.GetDirectories dir
        |> Array.collect (fun x -> FindFiles x pat)
        |> Array.append (Directory.GetFiles (dir, pat))
    with _ -> Array.empty
Title: Re: Findfile recursive ..
Post by: kaefer on November 12, 2010, 07:13:56 AM
It seems there's no need to use a sub function:
Code: [Select]
let rec FindFiles dir pat =
    try
        Directory.GetDirectories dir
        |> Array.collect (fun x -> FindFiles x pat)
        |> Array.append (Directory.GetFiles (dir, pat))
    with _ -> Array.empty

Oh, dear. Get ready for the next level:
Code: [Select]
let rec FindFiles dir pat =
    try [|  yield! Directory.GetFiles (dir, pat)
            for x in Directory.GetDirectories dir do yield! FindFiles x pat |]
    with _ -> Array.empty