Ordnerstruktur auslesen - Sortierung falsch

  • Excel

Es gibt 22 Antworten in diesem Thema. Der letzte Beitrag () ist von petaod.

    Ordnerstruktur auslesen - Sortierung falsch

    Hallo Zusammen,

    mit angehangenem Code wird eine gesamte Ordnerstruktur inklusive Unterordner eingelesen und jeweils in Spalten angezeigt.
    Soweit so gut. Funktioniert auch wunderbar.
    Heute habe ich gemerkt, dass es Schwierigkeiten mit der Sortierung von Zahlen gibt.

    Ordnerstruktur im Explorer Oberordner/Unterordner

    1
    2
    1 in 2
    10
    11
    1 in 11
    100

    Sortierung nach dem Einlesen in Excel

    1
    10
    100
    11
    1 in 11
    2
    1 in 2

    Wie und wo kann ich im Code festlegen, dass die eingelesenen Werte genau so dargestellt werden wie im Explorer?
    Danke im voraus!


    Quellcode

    1. Public Sub OrdnerListen_Start()
    2. Dim fso As Object
    3. With ActiveSheet
    4. .UsedRange.ClearContents
    5. Set fso = CreateObject("Scripting.FileSystemObject")
    6. Call OrdnerListen(fso, "E:\Test", .Range("A1")) ' Pfad anpassen!
    7. Set fso = Nothing
    8. End With
    9. End Sub
    10. Private Sub OrdnerListen(fso As Object, Ordnerangabe As String, rng As Range, Optional Zeile As Long, Optional Spalte As Long)
    11. Dim o, uo
    12. Set o = fso.GetFolder(Ordnerangabe)
    13. rng.Offset(Zeile, Spalte).Value = o.Name
    14. Zeile = Zeile + 1
    15. For Each uo In o.SubFolders
    16. Spalte = Spalte + 1
    17. Call OrdnerListen(fso, uo.Path, rng, Zeile, Spalte)
    18. Spalte = Spalte - 1
    19. Next
    20. Set o = Nothing
    21. Set uo = Nothing
    22. End Sub
    Alter Hut. Alles Strings. Und da wird Zeichen für Zeichen verglichen. Und wenn Du "4321" mit "1234567890" vergleichst. Dann kommt - weil 1 vor 4 kommt - die Reihenfolge raus, die Du nicht erwartest. Da müsstest Du schon die Zahl-Dateinamenteile in Integer umwandeln und dann sortieren. Etwas kompliziert, wenn es die Dateinamen neben der Extension nicht nur als Zahlen bestehen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Häufig von mir verwendete Abkürzungen: CEs = control elements (Labels, Buttons, DGVs, ...) und tDS (typisiertes DataSet)
    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht in den Spekulatiusmodus gehen.
    @VaporiZed
    Danke Dir erstmal.
    Vielleicht hätte ich erwähnen sollen, dass ich nicht besonders bewandert in VBA oder generell dem Programmieren bin.
    Dateinamen werden im Übrigen nicht dargestellt, nur rein die Ordnerstruktur mit den jeweiligen Unterordnern.
    Könntest Du mir einen Ansatz liefern, wie ich den Code anpassen müsste?
    Danke!
    Hallo Zusammen,

    sollte es mit dem aufgeführten Code nicht möglich sein, hat vlt jemand eine alternative Einlese-Routine, welche ich nutzen könnte.
    Wichtig wäre, dass die Verzeichnisstruktur der Ordner/Unterordner versetzt in den Spalten aufgelistet werden, ergo wie eine Baumstruktur und dann eben so sortiert, wie im Explorer gelistet.
    Dateien sollen nicht angezeigt werden.

    Wäre Klasse, wenn Ihr mir helfen könntet.

    MfG Madde
    Im Explorer bekommst du seit Windows 10 eine numerische Sortierreihenfolge.
    Das war übrigens nicht immer so und kann auch verändert werden.
    tenforums.com/tutorials/91417-…xplorer-windows-10-a.html


    In deinem Fall bist du auf die Lesereihenfolge von FileSystemObject.GetFolder angewiesen.
    Das kannst du nicht beeinflussen.
    Du kannst aber die eingelesene Collection SubFolders nach deinen Wünschen sortieren, bevor du sie verarbeitest.

    Oder du befüllst die Zellen mit einer Hilfsspalte, dass alle Pfade numerisch untereinander stehen und du auf die Zellen einen numerischen Sort-Vorgang anwenden kannst.

    Oder du akzeptierst es, wie es ist.
    Wo ist dabei das Problem?
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Wo ist dabei das Problem?


    Die Verzeichnisstruktur dient mir als Vorlage für den Druck von Registerblättern zwischen diversen Unterlagen damit diese nicht per Hand erstellt werden müssen.
    Hierbei ist daher wichtig, dass die Reihenfolge vom ersten bis zum letzten Ordner, inklusive der Unterordner stimmt, um sie komplett drucken zu können.

    MfG Madde
    Dann musst du deinen eigenen Sortiermechanismus einbauen, bevor du die Daten verarbeitest.
    Ich will ja mal nicht so sein.
    Ersetze deinen Code gegen folgenden:

    Visual Basic-Quellcode

    1. Option Explicit
    2. Dim fso As Object
    3. Public Sub OrdnerListen_Start()
    4. Set fso = CreateObject("Scripting.FileSystemObject")
    5. ActiveSheet.UsedRange.ClearContents
    6. ListFolders "D:\Test", ActiveSheet.Range("A1")
    7. End Sub
    8. Sub ListFolders(ByVal Path As Variant, ByRef c As Range)
    9. Dim p
    10. If Not IsObject(Path) Then Set Path = fso.GetFolder(Path) 'string to object
    11. c.Value = Path.Name
    12. Set c = c.Offset(1, 1)
    13. For Each p In OrderedList(Path.SubFolders)
    14. ListFolders p, c
    15. Next
    16. Set c = c.Offset(0, -1)
    17. End Sub
    18. Function OrderedList(ByVal List As Object) As Collection
    19. Dim coll As New Collection, p1 As Variant, i As Integer
    20. For Each p1 In List
    21. If coll.Count < 1 Then
    22. coll.Add p1
    23. Else
    24. For i = 1 To coll.Count
    25. If Val(p1.Name) < Val(coll(i).Name) Then
    26. coll.Add p1, Before:=i
    27. Exit For
    28. End If
    29. If i = coll.Count Then coll.Add p1, After:=i
    30. Next
    31. End If
    32. Next
    33. Set OrderedList = coll
    34. End Function
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    @petaod

    Hi, Du hattest mir damals sehr geholfen. Jetzt habe ich ein Problem mit diversen Ordnern.
    Normale Ordnernamen sind kein Thema aber wenn die Struktur wie folgt aufgebaut ist, sortiert er dann wieder falsch.

    7_4_1
    7_4_10
    7_4_11
    7_4_2
    7_4_20
    7_4_21
    7_4_22
    7_4_3
    7_4_4
    7_4_5
    7_4_6
    7_4_7
    7_4_8
    7_4_9

    vermutlich muss jeder Bereich zwischen den _ durchsucht und sortiert werden.
    Könntest Du mir hier nochmals unter die Arme greifen.

    Wäre total klasse!

    Gruß Madde
    Wenn innerhalb eines Ordners mehr als nur die letzte Zahl ändern kann, ist es nicht ganz trivial.
    Dann müssen jedesmal alle Zahlen durchsortiert werden.
    Mal sehen, vielleicht finde ich die nächsten Tage mal übrige Zeit.
    Versprechen tu ich mal nix.

    Aus wie vielen Ordnungszahlen besteht ein Verzeichnis maximal?
    Wie viele Stellen kann eine isolierte Ordnungszahl maximal erreichen?
    Was soll mit Ordnern geschehen, die nicht numerisch benannt sind?
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Ich denke, ein isolierter Ordner wird max zweistellig ( **_**_** ) sein, wenn dreistellig kein Problem darstellt, gerne dreistellig, um die Eventualität abzudecken.
    Nicht nummerisch benannte Ordner sollten sich, wie im Explorer, nach den nummerisch benannten Ordnern normal alphabetisch sortieren.

    Ich danke Dir vorab, unabhängig davon, ob Du Zeit finden wirst.

    Gruss Madde
    @petaod

    Ich würde gern nochmal einen Gedankengang einbringen. Reine Theorie.
    Die falsche Sortierung betrifft ja nur die Zahlen 1-9 (Zahlenbereich 1-99). Ist es vlt möglich, beim Einlesen allen diesen einstelligen Problem-Machern eine Null voranzustellen, damit die Zahlen/Text Sortierung gegeben ist.
    Beispiel aus 1.1.1 mach 01.01.01
    Sowie alles eingelesen ist sollte das Makro dann diesen"Zusatz"auch gleich wieder entfernen.
    Ist so etwas umsetzbar?

    MfG Madde
    Eine Abfrage auf größer oder kleiner wird bei Strings halt immer alphanumerisch vergleichen.
    Das lässt sich nur lösen, wenn man einen eigenen Comparer schreibt.
    Der muss die Dateinamen splitten, die beinhalteten Zahlen erweitern und danach vergleichen.

    Probier's mal so:

    Visual Basic-Quellcode

    1. Option Explicit
    2. Dim fso As Object
    3. Public Sub OrdnerListen_Start()
    4. Set fso = CreateObject("Scripting.FileSystemObject")
    5. ActiveSheet.UsedRange.ClearContents
    6. ListFolders "D:\Test", ActiveSheet.Range("A1")
    7. End Sub
    8. Sub ListFolders(ByVal Path As Variant, ByRef c As Range)
    9. Dim p
    10. If Not IsObject(Path) Then Set Path = fso.GetFolder(Path) 'string to object
    11. c.Value = Path.Name
    12. Set c = c.Offset(1, 1)
    13. For Each p In OrderedList(Path.SubFolders)
    14. ListFolders p, c
    15. Next
    16. Set c = c.Offset(0, -1)
    17. End Sub
    18. Function OrderedList(ByVal List As Object) As Collection
    19. Dim coll As New Collection, p1 As Variant, i As Integer
    20. For Each p1 In List
    21. If coll.Count < 1 Then
    22. coll.Add p1
    23. Else
    24. For i = 1 To coll.Count
    25. 'If Val(p1.Name) < Val(coll(i).Name) Then 'string comparison
    26. If NumericCompare(p1.Name, coll(i).Name) < 0 Then 'numeric comparison
    27. coll.Add p1, Before:=i
    28. Exit For
    29. End If
    30. If i = coll.Count Then coll.Add p1, After:=i
    31. Next
    32. End If
    33. Next
    34. Set OrderedList = coll
    35. End Function
    36. Function NumericCompare(ByVal s1 As String, ByVal s2 As String) As Integer
    37. s1 = NumericExtend(s1)
    38. s2 = NumericExtend(s2)
    39. If s1 > s2 Then NumericCompare = 1: Exit Function
    40. If s1 < s2 Then NumericCompare = -1
    41. End Function
    42. Function NumericExtend(ByVal s As String) As String
    43. Const Digits = 8
    44. Dim d As Variant, i As Integer, a() As String
    45. For Each d In Array(".", "-")
    46. s = Replace(s, d, "_")
    47. Next
    48. a = Split(s, "_")
    49. For i = LBound(a) To UBound(a)
    50. If IsNumeric(a(i)) And Len(a(i)) < Digits Then a(i) = Format(a(i), String$(Digits, "0"))
    51. Next
    52. NumericExtend = Join(a, "_")
    53. End Function
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Danke, dass Du nochmal rangegangen bist

    Läuft leider noch nicht ABER so weit weg kann das Ergebnis nicht liegen.
    Wenn die Struktur so angelegt ist: 1.1 Oberordner, 1.2 Oberordner, 1.10 Oberordner - dann ändert sich leider nichts, die 1.10 wird zwischen 1.1 und 1.2 einsortiert aber mir ist beim Testen aufgefallen, wenn die Zahl hinten ist
    Oberordner 1.1, Oberordner 1.2, Oberordner 1.10 - dann wird auch genau so nach den Zahlen sortiert.
    Wenn das jetzt noch gedreht werden kann, sollte es die Lösung sein.

    MfG Madde
    Dann pack mal in das Split-Array in Zeile 45 noch ein Blank mit rein.
    Bei​1.10 Oberordnerist die einzige Trennung beim Punkt.
    Das ​10 Oberordner wird nicht numerisch betrachtet und deshalb auch nicht erweitert.

    Hast du denn verstanden, wie die numerische Erweiterung funktioniert?
    Setz in Zeile 45 einen Haltepunkt, geh mit SingleStep durch und schau dir die Variablen an.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    Aufgrund mangelnder Programmierkenntnisse kann ich den Code leider nur bedingt verstehen.
    Von der Funktion her verstehe ich es so, dass der Ordnername bei Trennungen im Namen wie Blank, _ , - oder . auseinandergenommen und blockweise nach Zahlen durchsucht wird, um eine nummerischer Gliederung durchführen zu können.
    Der Hinweis mit dem "Blank" war letztlich die Lösung.

    Quellcode

    1. For Each d In Array(" ", ".", "-")


    Alle Testläufe mit verschiedenen Kombinationen waren nun erfolgreich.
    Ich danke Dir für Deine Unterstützung. Du hast mir extrem geholfen.

    MfG Madde

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Madde“ ()