Rekursive Dateisuche in .Net 4.5

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 19 Antworten in diesem Thema. Der letzte Beitrag () ist von simpelSoft.

    Rekursive Dateisuche in .Net 4.5

    Hallo.

    Und zwar wollte ich fragen, wie man eine Dateisuche (rekursiv) in .Net Framework 4.5
    realisieren würde.

    Ich hab hier im Forum schon ziemlich gute Codes gefunden (z.B Rekursive Dateisuche mit anonymer Methode) ,
    doch die Threads sind mittlerweile auch schon wieder etwas älter, von daher
    wollte ich mal fragen, ob .Net Framework 4.5 da mittlerweile noch bessere Möglichkeiten bietet.
    So spontan fällt mir nichts besseres ein.
    There is no CLOUD - just other people's computers

    Q: Why do JAVA developers wear glasses?
    A: Because they can't C#

    Daily prayer:
    "Dear Lord, grand me the strength not to kill any stupid people today and please grant me the ability to punch them in the face over standard TCP/IP."

    Daniel Baumert schrieb:

    noch bessere Möglichkeiten bietet.
    Nö.
    Was schwebt Dir denn vor?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    Daniel Baumert schrieb:

    doch die Threads sind mittlerweile auch schon wieder etwas älter, von daher
    wollte ich mal fragen, ob .Net Framework 4.5 da mittlerweile noch bessere Möglichkeiten bietet.


    Eine rekursive Dateisuche direkt über das Framework wird immer schnarch langsam im Vergleich zur passenden Win-API sein, egal ob das Framework 4.5 oder 10.0 heißt oder der Code, den Du gefunden hast toll ist.
    Auf was kommt es Dir an? Speed oder etwas anderes - erzähl mal...

    ErfinderDesRades schrieb:

    Kannst du das belegen?


    Ja, kann ich.
    Lass uns zusammenarbeiten - ok?
    Du baust eine kleine Suche per Framework und ich per API.
    Danach lassen wir beide Progs jeweils auf unseren Systemen laufen und schauen uns die Suchzeiten an.
    Wie wärs? Entweder mit Mini-GUI oder Console - wäre mir beides recht.

    simpelSoft schrieb:

    Lass uns zusammenarbeiten

    ErfinderDesRades schrieb:

    ja, das gfällt mir
    :thumbup:
    Vereinbart bitte genau, was die Algos tun sollen und was nicht, damit eine ein-eindeutige Abbildung aufeinander möglich ist.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    simpelSoft schrieb:

    Spezifikationen
    würde ich auch gern vorher einsehen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Fertig!

    VB.NET-Quellcode

    1. Imports System.IO
    2. Public Class Form2
    3. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    4. With FolderBrowserDialog1
    5. If .ShowDialog <> Windows.Forms.DialogResult.OK Then Return
    6. Me.Text = .SelectedPath
    7. Me.Update()
    8. Dim sw = Diagnostics.Stopwatch.StartNew
    9. Dim s = String.Format("Found {0} Files in {1}", CountFiles(.SelectedPath), sw.Elapsed.ToString)
    10. MessageBox.Show(s, .SelectedPath)
    11. End With
    12. End Sub
    13. Private Function CountFiles(ByVal path As String) As Integer
    14. CountFiles = 0
    15. 'rekursive anonyme Methode
    16. Dim recurse As Action(Of IEnumerable(Of DirectoryInfo)) = _
    17. Sub(dirs As IEnumerable(Of DirectoryInfo))
    18. For Each dirinf In dirs
    19. Try
    20. CountFiles += dirinf.GetFiles.Length
    21. Catch ex As UnauthorizedAccessException
    22. 'für manche Directories hat das Prog keine Rechte
    23. Continue For
    24. End Try
    25. 'selbst-aufruf
    26. recurse(dirinf.EnumerateDirectories)
    27. Next
    28. End Sub
    29. 'rekursion aufrufen
    30. recurse({New DirectoryInfo(path)})
    31. End Function
    32. End Class


    Du kannst einfach das Form nutzen, und vlt. einen 2. Button zufügen - dann wärs doch gut vergleichbar, oder?

    Was nicht jeder weiß: eine Messagebox kann man einfach mit Str-C auskopieren, zB hier ein Ergebnis:

    Brainfuck-Quellcode

    1. ---------------------------
    2. C:\Users\Account2
    3. ---------------------------
    4. Found 20784 Files in 00:00:01.8570900
    5. ---------------------------
    6. OK
    7. ---------------------------
    Dateien

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

    ErfinderDesRades schrieb:

    extrem unterschiedlich.
    Da sollten wir vielleicht Testbedingungen festlegen:
    1. Unmittelbar nach Hochfahren des Rechners, wo der ganze RAM jungfräulich ist.
    2. 10 Mal laufen lassen, dann aus n Läufen den Mittelwert bilden
    3. eine Datei erzeugen und den Test neu starten
    4. eine Datei verschieben und den Test neu starten
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Sorry - hat gedauert - muss nebenbei auch noch arbeiten ;) ..
    Habe da mal was zusammengefrickelt - VB.NET ist nicht so meine Domäne - wir können ja zusammen optimieren..
    Ihr habt Recht, bei mehreren Durchläufen gibts unterschiedliche Zeiten.
    Wobei die API deutlich schneller scheint.
    Getestet habe ich über die ganze C: Partition.
    Das ist dabei herausgekommen:

    EDR (links erster lauf, rechts zweiter Lauf)


    simpelSoft (links erster lauf, rechts zweiter Lauf)


    Projekt: FilesearchBenchmarks.zip
    Hey - jetzt hab ich nochmals getestet, diesmal nach komplettem Neustart des PC jeweils für EDR und simpelSoft.
    Nun liegen die Zeiten beim ersten Lauf nicht mehr so weit auseinander (!).
    Man kann trotzdem feststellen, dass die API schneller ist.

    EDR (erster Lauf nach Neustart links, zweiter Lauf rechts)


    simpelSoft (erster Lauf nach Neustart links, zweiter Lauf rechts)


    Falls sich Jemand wundert, warum unterschiedliche Filecounts gezeigt werden -> auf C: sind ständig Veränderungen vom System, mal sinds ein paar Dateien mehr, mal weniger..
    Ich hab dein Teil mal gehübscht, indem ich die Geschichte mitte anonymen rekursion reingebastelt hab (und paar kl Veränderungen)

    VB.NET-Quellcode

    1. Private Sub btsimpelSoft2_Click(sender As Object, e As EventArgs) Handles btsimpelSoft2.Click
    2. With FolderBrowserDialog1
    3. If .ShowDialog <> Windows.Forms.DialogResult.OK Then Return
    4. Me.Text = .SelectedPath
    5. Me.Update()
    6. Dim sw = Diagnostics.Stopwatch.StartNew
    7. Dim totSize As Long = 0
    8. Dim fCount As Integer = 0, dCount As Integer = 0
    9. EnumerateFilesystem(.SelectedPath, fCount, dCount, totSize)
    10. Dim output = {"SimpleSoft2",
    11. .SelectedPath,
    12. "Dateien: " & fCount.ToString("N0"),
    13. "Verzeichnisse: " & dCount.ToString("N0"),
    14. "Gesamtgröße: " & totSize.ToString("N0"),
    15. "Zeit: " & sw.Elapsed.ToString()}
    16. MessageBox.Show(String.Join(Environment.NewLine, output))
    17. End With
    18. End Sub
    19. Private Sub EnumerateFilesystem(rootDir As String, ByRef files As Integer, ByRef folders As Integer, ByRef fullSize As Long)
    20. Dim fls, fldrs As Integer, fllSz As Long
    21. Dim INVALID_HANDLE_VALUE As New IntPtr(-1)
    22. Dim findData As WIN32_FIND_DATA = Nothing
    23. Dim recurse As Action(Of String) = _
    24. Sub(directory)
    25. Dim findHandle = FindFirstFile("\\?\" & directory & "\*", findData)
    26. If findHandle = INVALID_HANDLE_VALUE Then Return
    27. Do
    28. If (findData.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) = 0 Then
    29. fls += 1
    30. fllSz += findData.nFileSizeLow + (CLng(findData.nFileSizeHigh) << 32)
    31. Else
    32. If findData.cFileName(0) = "."c Then Continue Do
    33. fldrs += 1
    34. recurse(Path.Combine(directory, findData.cFileName))
    35. End If
    36. Loop While FindNextFile(findHandle, findData)
    37. FindClose(findHandle)
    38. End Sub
    39. recurse(rootDir)
    40. files = fls
    41. folders = fldrs
    42. fullSize = fllSz
    43. End Sub
    Mir unbekannt ist der komische Directory-Prefix in #26 - wieso muss da "\\?\" & directory?

    ErfinderDesRades schrieb:

    Mir unbekannt ist der komische Directory-Prefix in #26 - wieso muss da "\\?\" & directory?

    Das kannste hier nachlesen: LINK
    Zitat: "Use CharSet=CharSet.Unicode, and prepend your filename to search for with "\\?\". This gives go access to filenames up to 32767 bytes in length.
    Use "\\?\UNC\" prefix for fileshares."


    Ich hab dein Teil mal gehübscht

    Danke fürs Aufhübschen! :thumbsup:

    PS: Ich hänge das Projekt (mit EDR Aufhübschungen) hier nochmal komplett ran - falls Jemand noch mehr optimieren möchte.
    Dateien

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „simpelSoft“ ()