Page 1 of 3 123 LastLast
Results 1 to 40 of 81

Thread: Directory Tree - Generates a list of subdirectories.

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,945

    Directory Tree - Generates a list of subdirectories.

    Directory Tree demonstrates how to list all subdirectories under a directory. Simply specify the "root" directory and output file.

    This can be useful, for example, when writing a program that searches for files.
    Last edited by Peter Swinkels; Nov 21st, 2015 at 11:44 AM. Reason: Multiple bug fixes.

  2. #2
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Peter Swinkels View Post
    Directory Tree demonstrates how to list all subdirectories under a directory. Simply specify the "root" directory and output file.

    This can be useful, for example, when writing a program that searches for files.
    Significantly faster method, is to request directories only, not all files.

    Hence the line...
    Code:
    Item = Dir$("*.*", vbArchive Or vbDirectory Or vbHidden Or vbSystem)
    should read.
    Code:
    Item = Dir$("*.", vbArchive Or vbDirectory Or vbHidden Or vbSystem)
    Difference in performance, is very significant - typically minutes, when there is large amount of directories and files within these.

  3. #3
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    Significantly faster method, is to request directories only, not all files.
    Note that the underlying APIs (FindFirstFile, etc.) will still enumerate files matching the specified pattern whether they are wanted or not.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  4. #4

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,945

    Re: Directory Tree - Generates a list of subdirectories.

    Thanks for the replies,

    Tech99: thanks for the suggestion. Why did you omit the last wild card (*. instead of *.*)? Directory names do sometimes have an extension.

    Bonnie West:
    Does this mean it doesn't really matter?

    Any way,
    Writing code, especially like this, is always balancing between readabilty and simplicity. Directly using the API probably would be fastest.

  5. #5
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Peter Swinkels View Post
    Directory names do sometimes have an extension.
    Too bad if the situation is that kind. Slows down substantially.

    We have instructed not to use '.' in directory names, in our file handling applications. Otherwise performance in file systems containing over 10k folders, would be very sluggish - as you are enumerating files also, usually tens of thousands to at least few hundred thousand.

  6. #6
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    Note that the underlying APIs (FindFirstFile, etc.) will still enumerate files matching the specified pattern whether they are wanted or not.
    Are you sure about that. Performance differs very very much between *.* vs. *. calls.

  7. #7

    Thread Starter
    Frenzied Member
    Join Date
    Feb 2003
    Posts
    1,945

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    Too bad if the situation is that kind. Slows down substantially.

    We have instructed not to use '.' in directory names, in our file handling applications. Otherwise performance in file systems containing over 10k folders, would be very sluggish - as you are enumerating files also, usually tens of thousands to at least few hundred thousand.
    Since my program is meant as a generic demonstration, I tried not to exclude anything for the sake of speed. If people feel they could use my code, they're perfectly free to make any changes they like, for whatever reason. So I'm probably going to leave the code "as is" for now. But I also understand your point about having to make certain sacrifices (such as omitting directory's with extensions in their name) in order to keep things fast.

    Thanks for the comments.
    Last edited by Peter Swinkels; Nov 15th, 2015 at 03:03 PM. Reason: typo

  8. #8
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Peter Swinkels View Post
    Since my program is meant as a generic demonstration, I tried not to exclude anything for the sake of speed.
    I fully understand that, and believe that others do also. However my point in this subject is to clarify subject where 'wrong coding' easily leads to 'unusable application'*. Been there done that.

    *Poor performance when files and folders count is largish.

    For the better performance one might use FindFirstFileEx API using FindExInfoBasic and FIND_FIRST_EX_LARGE_FETCH flags.

    Even better perfomance is achieved using NtQueryDirectoryFile API.

    aaand... best performance is achieved by using either of the previous methods and ditching NT as a file server altogether and using fex. RHE Linux and Samba shares = two to three fold better in file system performance.**

    ** or in NT case, code a system driver which reads and parses MFT, then entire disk folders- and files names can be read in within few seconds - regardless of folder and file count.

  9. #9
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Peter Swinkels View Post
    Bonnie West:
    Does this mean it doesn't really matter?
    Quote Originally Posted by Tech99 View Post
    Are you sure about that. Performance differs very very much between *.* vs. *. calls.
    According to the documentation, FindFirstFile "searches a directory for a file or subdirectory with a name that matches a specific name (or partial name if wildcards are used)."

    What that means is that the search pattern cannot guarantee that only files or only folders will be found. Files & folders can both have dot (.) characters in their names and it is also perfectly possible for both of them to not have any dot characters in their names.

    Here's an example. Consider a directory that contains these files & folders:

    New Folder
    New.Folder
    New Text Document txt
    New Text Document.txt

    The *.* search pattern would match all 4 of those files & folders. The *. search pattern, OTOH, would match New Folder and New Text Document txt.

    So, as you can see, it isn't possible to instruct FindFirstFile to return files only or folders only. Performance differs of course because files usually have extension names and excluding them from the search will indeed result in a much faster directory listing.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  10. #10
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    Files & folders can both have dot (.) characters in their names and it is also perfectly possible for both of them to not have any dot characters in their names.
    Yes i know, i should have been more specific in description.

    Now when you request folders using *.* the api function returns all files and folders. Very large amount of items in worst case, then when you request folder names using *. only the file count drops substantially and performance is much better - of course, after Findfile - one should filter out files using directory flag comparison.

    We typically have customer systems thousands of folders, where file count easily exceeds 20k, that makes significant difference and is easily handled limiting/prohibiting using dot in folder names.

    Code:
    'part of...
    Sub RecurseFolder (ByRef pstrFolder As String)
    Dim lngHandle As Long
    Dim strFile As String
    Dim typFind As WIN32_FIND_DATA
    
    If Right$(pstrFolder, 1) = "\" Then pstrFolder = Left$(pstrFolder, Len(pstrFolder) - 1)
    lngHandle = FindFirstFile(pstrFolder & "\*.", typFind)
        Do While lngHandle <> INVALID_HANDLE_VALUE
            strFile = Left$(typFind.cFileName, InStr(typFind.cFileName, vbNullChar) - 1)
            If (typFind.dwFileAttributes And vbDirectory) = vbDirectory Then
                If Left$(strFile, 1) <> "." Then
                   RecurseFolder pstrFolder & "\" & strFile
    Last edited by Tech99; Nov 16th, 2015 at 03:09 PM.

  11. #11
    Addicted Member
    Join Date
    Jun 2002
    Location
    Finland
    Posts
    169

    Re: Directory Tree - Generates a list of subdirectories.

    Here is very fast enumerator (EnumFolders.zip)
    http://www.vbforums.com/showthread.p...=1#post4936619

  12. #12
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by pekko View Post
    Here is very fast enumerator (EnumFolders.zip)
    http://www.vbforums.com/showthread.p...=1#post4936619
    On the contrary. Poor performance, when only folder names needs to enumerate... but little change makes it perform. Altought this version could not use '*.' notation, hence slower than method above.

    However i am planning to write enumeration class using ntQueryFileDirectory, which should be bit faster, expecially in network shares.


    Code:
    Public Sub EnumFolders(ByVal sPath As String, _
                           Optional ByVal sPattern As String = "*.*", _
                           Optional ByVal lAttributeFilter As FileAttributes = Attr_ALL, _
                           Optional ByVal bRecurse As Boolean = True)
       Dim lHandle As Long
       Dim sName As String
       Dim Lines As Long
       Dim lPtr As Long
    
       lPtr = VarPtr(wFD)
    
       On Error GoTo ProcedureError
    
       sPath = QualifyPath(sPath)
    
       lHandle = FindFirstFileW(StrPtr("\\?\" & sPath & sPattern), lPtr)
       If lHandle > 0 Then
          Do
             With wFD
                sName = TrimNull(.cFileName)
                   If (.dwFileAttributes And vbDirectory) Then
                      If bRecurse Then
                         If AscW(sName) <> vbDot Then   'skip . and .. entries
    1. added           RaiseEvent ItemDetails(sPath, sName) 'Added line
                            EnumFolders sPath & sName, sPattern, lAttributeFilter, bRecurse
                         End If
                      End If
    2. comm       'ElseIf (.dwFileAttributes And lAttributeFilter) Then 'Commented out
    3. ented out  'RaiseEvent ItemDetails(sPath, sName) 'Commented out
                   End If
             End With
          Loop While FindNextFileW(lHandle, lPtr) > 0
       End If
       FindClose lHandle
       Exit Sub
    ProcedureError:
       Debug.Print "Error " & Err.Number & " " & Err.Description & " of EnumFolders"
    End Sub
    Last edited by Tech99; Nov 16th, 2015 at 05:49 PM.

  13. #13
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by pekko View Post
    Here is very fast enumerator (EnumFolders.zip)
    http://www.vbforums.com/showthread.p...=1#post4936619
    I actually did some comparisons of the codes in that thread back then but I hesitated to post them because the OP no longer seems interested. I've posted them now, in case somebody else is interested those codes.



    @ Tech99

    You may want to give this reworked version of my code in that thread a try.


    Name:  List Folders Demo.png
Views: 2768
Size:  9.0 KB
    Attached Files Attached Files
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  14. #14
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    @ Tech99

    You may want to give this reworked version of my code in that thread a try.
    Do you mean Enumfolders Modifed sample?
    http://www.vbforums.com/attachment.p...5&d=1447745715

    That is slow, because it does not enumerate folders only, but also files. Tested it against my code to one file share.

    116 folders share. Enumfolders modified took around 16 seconds and true folders only enumeration took sub one second.
    17418 folders, with over half million files share. Enumfolders modified took around 13 minutes and true folders only enumeration took about 2.3 second.
    Attached Images Attached Images  

  15. #15
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    Name:  List Folders Demo.png
Views: 2768
Size:  9.0 KB
    This version (List folders.zip post #13 in this thread) performance is acceptable, 17418 folders, took about 7.3 second.

    Difference to my code, comes mainly from listing folders, when in my version folders are only read to array.

    So the *.* vs *. do really matter. It would be interesting to see how NtQueryDirectoryFile would perform.
    Last edited by Tech99; Nov 17th, 2015 at 02:33 PM.

  16. #16
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Here is Bonney West last submitted version (List folders.zip post #13 in this thread) a bit optimized -> half second better performance per 10k path count.

    Modifiation to the mnuBrowse_Click() subroutine (add three lines).
    Code:
    ListFolders sPath, "*." '<-- The "*." pattern fails to list folder names such as "New.Folder"
    'ListFolders sPath, "*.*" '<--The "*.*" pattern is bit slower, but would find folder names such as New.Folder"
    
    'Add these next three lines to the mnuBrowse_Click() subroutine
    For i = LBound(dirNames) To UBound(dirNames)
        SendMessage m_hWndLB, LB_ADDSTRING, 0&, StrPtr(dirNames(i))
    Next i
    Replace whole ListFolders subroutine, with this code.
    Code:
    Private Sub ListFolders(ByRef FolderPath As String, Optional ByRef Pattern As String = "*")
    'NOTE!!!                      FolderPath should not end in a trailing backslash (\)
    Const ALLOC_CHUNK = 10&
    Dim hFindFile As Long
    Dim i As Long
    Dim Length As Long
    Dim SubFolder As String
    Static lCount As Long
    
    hFindFile = FindFirstFile(FolderPath & "\" & Pattern, m_WFD)
    
    If hFindFile <> INVALID_HANDLE_VALUE Then
        Do        'Process folders only (junctions, symlinks & mounted folders won't be recursed)
            If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT)) And Asc(m_WFD.cFileName) <> vbDot Then
                Length = lstrlen(m_WFD.cFileName)
                SubFolder = Left$(m_WFD.cFileName, Length)
                lCount = lCount + 1
                ReDim Preserve dirNames(lCount) As String
                dirNames(lCount) = FolderPath & ("\" & SubFolder & "\")
                ListFolders FolderPath & ("\" & SubFolder), Pattern 'Recurse subfolders
            End If
        Loop While FindNextFile(hFindFile, m_WFD)
    
        hFindFile = FindClose(hFindFile): Debug.Assert hFindFile
    End If
    End Sub
    Add to module or form level.
    Code:
    Private Const vbDot = 46
    Dim dirNames() As String
    Last edited by Tech99; Nov 17th, 2015 at 10:43 PM.

  17. #17
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    Do you mean Enumfolders Modifed sample?
    http://www.vbforums.com/attachment.p...5&d=1447745715
    No, I was referring to the attachment in my post.

    Quote Originally Posted by Tech99 View Post
    So the *.* vs *. do really matter.
    Yes, the search pattern greatly influences indeed the amount of file and folder names that FindFirstFile will return. However, note that the *. pattern does not filter out names such as ".Folder" or "..File".

    Quote Originally Posted by Tech99 View Post
    Code:
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT)) And Asc(m_WFD.cFileName) <> vbDot Then
    In the original code:

    Code:
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT)) = FILE_ATTRIBUTE_DIRECTORY Then
    the highlighted part served to ensure that only regular folders were processed. Junctions, symbolic links and mounted folders all have the FILE_ATTRIBUTE_REPARSE_POINT flag set, so in order to skip them, the expression must include the highlighted portion above.

    Regarding the testing of the "." and ".." entries, code that utilizes the Asc(W) function fails to take into account file & folder names that begins with the dot character. Such names (which are more like extension-only names) are legal and are actually not really that rare (at least in my system).
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  18. #18
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    No, I was referring to the attachment in my post.
    Yes, so i thought also, just asking for.

    Yes, the search pattern greatly influences indeed the amount of file and folder names that FindFirstFile will return. However, note that the *. pattern does not filter out names such as ".Folder" or "..File".
    Sure we know that - however one must bear in mind that most files do have an extension and folders do not - at least when prohibited to use dot when naming folders, so that - in well doumented and instructed to userland - does significant difference.

    ...and when your search pattern is nailed to '*.' user does not find incorrectly named folders (if using explorer etc. 'standard' tooling to create/rename), so that '*.' steers them very effectively to follow rules.

    Regarding the testing of the "." and ".." entries, code that utilizes the Asc(W) function fails to take into account file & folder names that begins with the dot character. Such names (which are more like extension-only names) are legal and are actually not really that rare (at least in my system).
    Yes, that also is by purpose/design.

  19. #19
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    Code:
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT)) = FILE_ATTRIBUTE_DIRECTORY Then
    the highlighted part served to ensure that only regular folders were processed. Junctions, symbolic links and mounted folders all have the FILE_ATTRIBUTE_REPARSE_POINT flag set, so in order to skip them, the expression must include the highlighted portion above.
    So what is the difference in short circuiting that to...
    Code:
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT))
    Evaluates to True also, so the expression does not need to include the highlighted portion above.

  20. #20
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    So what is the difference in short circuiting that to...
    Code:
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT))
    Evaluates to True also, so the expression does not need to include the highlighted portion above.
    That expression is checking for both FILE_ATTRIBUTE_DIRECTORY and FILE_ATTRIBUTE_REPARSE_POINT bit flags. (If we neglect to check for FILE_ATTRIBUTE_REPARSE_POINT, we could possibly recurse into a junction, symbolic link or mounted folder and we normally don't want to do that [theoretically, infinite recursion could happen].) In order for the test to succeed, only the FILE_ATTRIBUTE_DIRECTORY bit must be set (if FILE_ATTRIBUTE_REPARSE_POINT is also set, then the entire expression evaluates to False). That is the purpose of the equality test at the end.


    BTW, most of the folder names in my system that either contains or begins with the dot character weren't created by me. Programs such as GIMP, Java, Pale Moon, Notepad++ and even Windows itself (see e.g. the winsxs folder) all created folders that contained dot characters without my intervention. IMO, if one is going to write a generic directory walker code that uses FindFirstFile & co., details like dot characters in folder names and the possibility of encountering junctions, symbolic links and mounted folders must be taken into account.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  21. #21
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Ok, i see - excellent point, so i stand corrected.

    Directory evaluation corrected:
    Code:
    'dot is not allowed in directory names
    If (m_WFD.dwFileAttributes And (FILE_ATTRIBUTE_DIRECTORY Or FILE_ATTRIBUTE_REPARSE_POINT)) = FILE_ATTRIBUTE_DIRECTORY And (Asc(m_WFD.cFileName) <> vbDot) Then
    As what comes to hard/soft/symbolic links or junctions - it seems that there is none, other than those Windows OS generated ones (All Users, Application Data, Documents etc.).
    Users typically are not creating/defining those, neither do engineering or other apps we use. Briefly checked and did not find dot containing folder names from Notepad++ or Gimp installations, Java nor Pale Moon browser we don't even run.
    Last edited by Tech99; Nov 18th, 2015 at 04:58 PM.

  22. #22
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    Here is my unicode class. In my example fill a RTB with all folders from C.
    Class do some nice things and is extracted from M2000 Interpreter (the I use it to fill a user control, a special list box that can be show folders and files in a form of tree).
    In a form only these lines are enough to get all folders along the path. Because list can hold files too, we have to use mid$() to skip the folder marker. So if you make NoFiles as False you get the files too.

    Code:
    Dim md As New recDir
    Private Sub Form_Load()
    Dim a$, i As Long, k As Long
    RichTextBox1 = ""
    md.Nofiles = True
    a$ = md.Dir2("C:\", , True)
    Me.Caption = md.listcount
    k = 1
    For i = 1 To md.listcount
    RichTextBox1.SelStart = k
    a$ = Trim$(Str$(i)) + " " + Mid$(md.List(i), 2) + vbCrLf
    k = k + Len(a$)
    RichTextBox1.SelText = a$
    Next i
    End Sub

    folders.zip

  23. #23
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    Replace the form code from previous example, and you can use with Events the recDir class. You can stop the searching by using the close button on window.


    Code:
    Dim WithEvents md As recDir, working As Boolean, getout As Boolean
    Dim k As Long, i As Long
    Private Sub Form_Load()
    Set md = New recDir
    Dim a$, i As Long, k As Long
    k = 1
    Show
    working = True
    RichTextBox1 = ""
    md.Nofiles = True
    laststr = "C:\"
    a$ = md.Dir2("C:\", , True)
    
    
    End Sub
    
    Private Sub Form_Resize()
    If Me.ScaleHeight > 1000 And Me.ScaleWidth > 1000 Then
    RichTextBox1.Move 0, 0, Me.ScaleWidth, Me.ScaleHeight
    End If
    End Sub
    
    Private Sub Form_Terminate()
    Set md = Nothing
    End Sub
    
    Private Sub Form_Unload(Cancel As Integer)
    md.abort = True
    If working Then Cancel = True: getout = True
    End Sub
    
    Private Sub md_DirFinished()
    working = False
    If getout Then
    Unload Me
    Else
    Me.Caption = md.listcount
    MsgBox "finished"
    End If
    End Sub
    
    Private Sub md_feedback(FileName As String)
    RichTextBox1.SelStart = k
    i = i + 1
    'a$ = Trim$(Str$(i)) + Space$(md.ReadLevel(md.listcount - 1) + 1) + FileName + vbCrLf
    
    a$ = Trim$(Str$(i)) + md.FindFolder(md.listcount - 1) + Mid$(FileName, 2) + vbCrLf
    
    
    k = k + Len(a$)
    RichTextBox1.SelText = a$
    End Sub

  24. #24
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by georgekar View Post
    Replace the form code from previous example, and you can use with Events the recDir class.
    Tested this, same path than previous tests, expect that users have greated 6 folders more (17418 vs. 17424).

    Takes quite considerable amount of time (over minute) and little bit more memory than versions above.
    Attached Images Attached Images  

  25. #25
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    As what comes to hard/soft/symbolic links or junctions - it seems that there is none, other than those Windows OS generated ones (All Users, Application Data, Documents etc.).
    Users typically are not creating/defining those, neither do engineering or other apps we use.
    Yeah, junctions and symbolic links are generally underused in Windows. Mounted folders, however, might be slightly more common.

    Quote Originally Posted by Tech99 View Post
    Briefly checked and did not find dot containing folder names from Notepad++ or Gimp installations, Java nor Pale Moon browser we don't even run.
    • GIMP created ".gimp-2.8" and ".thumbnails" folders under my user profile folder.
    • Java created "jre1.8.0_51" and "jre1.8.0_60" folders under its installation directory.
    • Pale Moon (and most likely other FireFox based browsers) created 2 "*.default" folders under the 2 "Profiles" folder in the "AppData" directory.
    • Notepad++ created a "user.manual" folder under its installation directory.
    • Finally, and I don't know how this got into my system, Microsoft (?) created a "Microsoft.NET" folder in the "Program Files" directory.

    The point Peter Swinkels and I are trying make is that the "*." pattern is not a totally fool-proof way of filtering out files and returning folders only. Even if your users were told to avoid using the dot character in their folder names, some programs may just be out of your control. FindFirstFile et al. are probably not the best choice for you if you require both rapid searching and folders-only enumeration.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  26. #26
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    Tech99 ,
    Using this line you can add spaces but not the full path
    a$ = Trim$(Str$(i)) + Space$(md.ReadLevel(md.listcount - 1) + 1) + FileName + vbCrLf

    As you see for each full path need a search in the list. So the right job is to show the folders, using the level and when the user click on a folder then one time he get the search.
    The think about the use of a level and only a name is for the minimum need to store information. We don't have to repeat each path in each line. So you get the minute because using md.FindFolder(md.listcount - 1) in each line add more time to final loop.

    If you see the class recDir there is method to define a stop level (say 3 sub folders), and you can select the sorting method

    In my code in my sign you find my M2000 Interpreter. There I have a control I made using this class (In the demo above I put a small function that leaves in a module in M2000). The control show a directory, or a tree of files and can search in the background using the code asynchronously. And if you see you can break the search at any time. But if you see the code there is a Doevents in the code that is calling using a MOD operator. So if you change the number of Doevents that occur, the rate of that, you get a faster or slower search.

    Another way to use RecDir class is by using it to fill internal array once :

    Code:
    Sub testme(p$, tp$)
    Dim md As New recDir, offset As Long
    
    offset = Len(p$) + 1
    md.LevelStop = 1
    md.SortType = 2  ' change that
    a$ = md.Dir2(p$, tp$)
    Do
    a$ = md.Dir2()
    If a$ <> "" Then Debug.Print a$ Else Exit Do
    Loop
    md.Nofiles = True
    
    a$ = md.Dir2(p$)
    Do
    a$ = md.Dir2()
    If a$ <> "" Then Debug.Print Mid$(a$, offset) Else Exit Do
    Loop
    End Sub
    Last edited by georgekar; Nov 19th, 2015 at 04:22 AM.

  27. #27
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    You didn't read my post at all?

    So i clarify my point of view once more. We don't care if application creates it's own dotted folder names (for thumbnails or whatever) - those folders are not project data folders under data folder tree created by project people ie. where engineers, designers, accoutants etc. store their work files.

  28. #28
    PowerPoster Arnoutdv's Avatar
    Join Date
    Oct 2013
    Posts
    6,734

    Re: Directory Tree - Generates a list of subdirectories.

    Like Bonnie already said you can not say you should not use "." in folder names and ignore folders which do have "." in their name.
    This should be a generic code submission.
    So others can use it as a template and adapt it to their needs.

  29. #29
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    You didn't read my post at all?
    I did, and I believe I understood every word you wrote pretty well.

    Quote Originally Posted by Tech99 View Post
    So i clarify my point of view once more. We don't care if application creates it's own dotted folder names (for thumbnails or whatever) - those folders are not project data folders under data folder tree created by project people ie. where engineers, designers, accoutants etc. store their work files.
    The only reason why I joined this thread was because you stated in your post #2:

    Quote Originally Posted by Tech99 View Post
    Significantly faster method, is to request directories only, not all files.
    Since my post #3, I have been trying to point out to you that that method works well only in your particular case. Other programmers, especially "those junior coders", who will come to this thread in the future might get the impression that it's OK to use the "*." pattern if all they want to enumerate are folders only. Well, it is not, as my demonstrations above have shown.


    You mentioned above that you were planning on writing an enumeration class using NtQueryDirectoryFile. I'm not familiar with that API, but if it has the capability to enumerate folders only (and do it quickly), then there is probably no more reason to forbid your users from using the dot character in folder names.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  30. #30
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    You mentioned above that you were planning on writing an enumeration class using NtQueryDirectoryFile. I'm not familiar with that API, but if it has the capability to enumerate folders only (and do it quickly), then there is probably no more reason to forbid your users from using the dot character in folder names.
    Not sure about that yet, but NtQuery is fastest method to filesystem driver.

    For the directory only enumeration there is FindFirstFileEx API, found out that in yesterday, when studying this matter. To modify your sample to use EX version.

    Code:
    'Add to declaration section
    Private Enum FINDEX_INFO_LEVELS
      FindExInfoStandard = 0&
      FindExInfoBasic = 1&      'supported in W7 and newer
      FindExInfoMaxInfoLevel = 2&
    End Enum
    
    Private Enum FINDEX_SEARCH_OPS
        FindExSearchNameMatch = 0&
        FindExSearchLimitToDirectories = 1&
        FindExSearchLimitToDevices = 2&
        FindExSearchMaxSearchOp = 3&
    End Enum
    
    Private Const FIND_FIRST_EX_LARGE_FETCH = 2
    
    Private Declare Function FindFirstFileEx Lib "kernel32.dll" Alias "FindFirstFileExA" (ByVal lpFileName As String, _
    ByVal FindExInfoLevel As FINDEX_INFO_LEVELS, lpFindFileData As WIN32_FIND_DATA, ByVal FindExSearchOp As FINDEX_SEARCH_OPS, lpSearchFilter As Any, ByVal dwAdditionalFlags As Long) As Long
    
    'Change FindFirstFile call to FindFirstFileEx call in Private Sub ListFolders.
    'hFindFile = FindFirstFile(FolderPath & "\" & Pattern, m_WFD)
    hFindFile = FindFirstFileEx(FolderPath & "\" & Pattern, FINDEX_INFO_LEVELS.FindExInfoBasic, m_WFD, FINDEX_SEARCH_OPS.FindExSearchLimitToDirectories, 0&, 0&)
    Difference in performance is about one second per 1.2K folders, when pattern is '*.' and bit more than that when pattern is '*.*'.
    Now the '*.*' pattern performs quite well in large filesystems.

  31. #31
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Tech99 View Post
    Code:
    Private Declare Function FindFirstFileEx Lib "kernel32.dll" Alias "FindFirstFileExA" (ByVal lpFileName As String, _
    ByVal FindExInfoLevel As FINDEX_INFO_LEVELS, lpFindFileData As WIN32_FIND_DATA, ByVal FindExSearchOp As FINDEX_SEARCH_OPS, lpSearchFilter As Any, ByVal dwAdditionalFlags As Long) As Long
    If your program is only being used in NT-based OSs, then you can improve the performance some more by just simply replacing all ANSI APIs with their Unicode counterparts. Of course, that means you'll either need to use StrPtr() when passing Strings or you'll have to set a reference to a type library where the Unicode APIs are declared.

    Quote Originally Posted by MSDN
    Unicode and ANSI Functions

    When Microsoft introduced Unicode support to Windows, it eased the transition by providing two parallel sets of APIs, one for ANSI strings and the other for Unicode strings. For example, there are two functions to set the text of a window's title bar:

    • SetWindowTextA takes an ANSI string.
    • SetWindowTextW takes a Unicode string.

    Internally, the ANSI version translates the string to Unicode. The Windows headers also define a macro that resolves to the Unicode version when the preprocessor symbol UNICODE is defined or the ANSI version otherwise.

    Code:
    #ifdef UNICODE
    #define SetWindowText  SetWindowTextW
    #else
    #define SetWindowText  SetWindowTextA
    #endif
    In MSDN, the function is documented under the name SetWindowText, even though that is really the macro name, not the actual function name.

    New applications should always call the Unicode versions. Many world languages require Unicode. If you use ANSI strings, it will be impossible to localize your application. The ANSI versions are also less efficient, because the operating system must convert the ANSI strings to Unicode at run time. Depending on your preference, you can call the Unicode functions explicitly, such as SetWindowTextW, or use the macros. The example code on MSDN typically calls the macros, but the two forms are exactly equivalent. Most newer APIs in Windows have just a Unicode version, with no corresponding ANSI version.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  32. #32
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by Bonnie West View Post
    If your program is only being used in NT-based OSs...
    Yeah i know and that is the one problem, customer base has, among the others older (4 and even 3.51) NT machines. 'The story' they telling goes - no need to change os, because those versions work. Couple of customers even run Wine.

  33. #33
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    Bonnie West
    I provide a unicode solution above, with sorting routine. You can alter to match your needs..Works with events also. Just tell me if you see it.

  34. #34
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    One scenario with FindFirstFileEx API which needs to measure, came to my mind. Enabling FIND_FIRST_EX_LARGE_FETCH flag and trying with search pattern '*'. Performance could be even better, if that kind of call would automatically recurse subfolders.

    hFindFile = FindFirstFileEx(FolderPath & "\" & Pattern, FINDEX_INFO_LEVELS.FindExInfoBasic, m_WFD, FINDEX_SEARCH_OPS.FindExSearchLimitToDirectories, 0&, FIND_FIRST_EX_LARGE_FETCH)

    Edit, tested performance, bit mixed results. Windows 7 workstation benefited enabling FIND_FIRST_EX_LARGE_FETCH flag and setting pattern to '*'. Server search did not, actually it was bit slower than querying without large fetch flag.

    W7 workstation, 1285 folders
    pattern *.* -> 6.8731, 6.9714 and 6.8767 seconds.
    Pattern * and Large_Fetch -> 5.3779, 5.4598, 5.5258 seconds.

    W12K R2 server, 19459 folders
    Pattern *.* -> 3.1201, 3.1146, 3.1199 seconds.
    Pattern * and Large_Fetch -> 3.2430, 3.2397, 3.2519 seconds.

    W12K R2 server, via share 17434 folders
    Pattern *.* -> 26.1318, 26.5813, 26.5810 seconds.
    Pattern * and Large_Fetch -> 24.6481, 24.5381, 24.5071 seconds.

    Interesting that server machine performs lesser when FIND_FIRST_EX_LARGE_FETCH flag is enabled.

    btw... adding 19459 folders to listbox took 9.5 seconds (mean).

    Quite a suprise is that the SMB perfomance is so much lesser (cpu Xeon E5 2620 v3 with 12 cores, 40 Gb memory, 4 x gigabit network, Smart Array P440ar controller), tuning tips are welcome.

    Increase AdditionalWorkerThreads or what to try/do?
    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    https://redmondmag.com/articles/2014...-problems.aspx
    https://technet.microsoft.com/en-us/.../jj134210.aspx
    Last edited by Tech99; Nov 20th, 2015 at 11:59 AM. Reason: Edit, tested performance.

  35. #35
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by georgekar View Post
    Bonnie West
    I provide a unicode solution above, with sorting routine. You can alter to match your needs..Works with events also. Just tell me if you see it.
    Thanks, georgekar! Yeah, I've already seen your attachment in post #22. I hope you don't mind, but I favor a different approach when it comes to optimizing directory enumeration. I prefer to do things as directly as possible so that intermediate "steps" such as Events are skipped.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  36. #36
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    More faster (more than 3 times faster)
    Form1.zip

    I do an optimization. Before I had a general IsDir() function, But now because I have "data" for attribute I know when I have folder. Secondly I put in raiseevent the foldername and all folders.
    Check the code above.

  37. #37
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by georgekar View Post
    More faster (more than 3 times faster)...
    I think that you possibly were measuring cached performance. Tested noncached performance, it took 72 seconds - so 5 second progress to previous version.

  38. #38
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    Tech99
    There is a huge directory in windows 7, C:\Windows\winsxs with 6808 folders and 6800 of them with many dots in name. if you exclude that folders then you gain time, but you have miss a lot....

  39. #39
    Frenzied Member
    Join Date
    May 2014
    Location
    Kallithea Attikis, Greece
    Posts
    1,309

    Re: Directory Tree - Generates a list of subdirectories.

    And what you mean noncached performance...Does Windows cache all directories of C:\

  40. #40
    Fanatic Member
    Join Date
    Apr 2015
    Location
    Finland
    Posts
    692

    Re: Directory Tree - Generates a list of subdirectories.

    Quote Originally Posted by georgekar View Post
    And what you mean noncached performance...Does Windows cache all directories of C:\
    No, i didn't test against C:\ folder, but the same data folder structure used in other previous tests, so there were no dots in directory names. Windows somewhat caches ie. when you read folder structure second time, time taken drops - so to get true measurement this must be dealt - either flush cahce or disable caching altogether when testing.

    https://msdn.microsoft.com/en-us/lib...(v=vs.85).aspx
    Last edited by Tech99; Nov 21st, 2015 at 12:03 PM.

Page 1 of 3 123 LastLast

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width