DuplicateFinder | Version: 1.0

    • Release

    Es gibt 34 Antworten in diesem Thema. Der letzte Beitrag () ist von kevios11.

      DuplicateFinder | Version: 1.0

      Name des Programms:
      DuplicateFinder

      Beschreibung:
      Der DuplicateFinder durchsucht rekursiv einen vom User gewählten Ordner und filtert nach doppelten Dateien, die allerdings auch unterschiedlich heißen können. Die Dateien werden mittels einem Sha1-Hash verglichen und anschließend aufgelistet. Dort kann man manuell oder automatisch die doppelten Dateien markieren und sie anschließen löschen lassen. Mit Rechtsklick auf eine Zeile kann man die Datei öffnen.

      Screenshot(s):


      Verwendete Programmiersprache:
      Visual Basic.NET (IDE: VB 2008)

      Systemanforderungen:
      .NET Framework 2.0

      Download:
      DuplicateFinder.rar (112 KB / 1,14MB)

      Lizenz/Weitergabe:
      Freeware, Closed Source
      Getestet: Funktioniert einwandfrei! Bin meinem Bilder Ordner durchgegangen(~1.000 Dateien), hat super funktioniert ;).

      Kleiner Tipp zur Geschwindigkeit: Wie wäre es erst mit CRC32 zu prüfen und wenn ein Duplikat gefunden wurde noch einmal mit SHA-1 Hash prüfen(Um Kollision gering zu halten).
      Würde die Geschwindigkeit etwas erhöhen.

      Eine Option um alle Unterordner mit einzubeziehen wäre auch noch ein schöner Zusatz :>

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

      Rekursive Dateisuche = alle Unterordner
      Ansonsten: nettes Programm. Blockiert mir aber die Festplatte wenn ich meinen Dateien-Ordner (>200GB, >4k Dateien) durchsuche -> kann keine Musik mehr hören

      Solltest evtl. die Lesegeschwindigkeit anpassen.
      Außerdem: bei einer Datei die groß genug ist (>4 GB)

      Beim Klick auf "Cancel" und dem Beenden der Anwendung blieb der Prozess noch erhalten.
      Nachtrag: Außerdem weiß ich, dass ich bei knapp 4k Dateien (die untersucht wurden) keine 500 Duplikate habe.
      Das mit dem CRC32 könnte ich mir mal ansehen bzw. könnte ich dieses Prinzip auch einfach auf die sha1 Funktion anwenden, einfach erstmal einen festen Buffer (4096 Bytes) auslesen und nur bei einer Kollision von beiden Dateien den sha1-Hash bilden, das eigentlich eine gute Idee.

      Nunja, das die Festplatte blockiert wird lässt sich glaube ich nicht vermeiden, da eben jede Datei angefasst und eben via ReadAllBytes() eingelesen wird.
      Ebenso dass das Programm soviel RAM verbraucht, weil die Datei ja in eine Variable gelesen wird um sie dem Sha1ProviderService zuzuweisen. Aber mit der CRC32 bzw. festen Buffer auslesen anpassung, dürfte sich das auch erledigen denke ich.

      Hast du Cancel beim Durchsuchen der Dateien oder beim suchen der Duplikate gedrückt? Sind 2 verschiedene Abläuft, erstmal werden alle Ordner nach Dateien durchsucht und danach wird die Liste der Dateien druchgegangen, der Hash erstellt und nach Duplikaten gesucht.

      Wenn wirklich 500 Duplikate gefunden wurden, hast ja die Möglichkeit in der Result Liste nachzusehen ob es wirklich Duplikate sind, alle Duplikate sind immer Farblich abwechselnt Gruppiert. Als ich mein Bilderordner durchsucht habe, waren alle Duplikate wirkliche Duplikate.

      @Manawyrm: das auch eine super Idee ... man war wohl gestern zu spät das ich auf so einfache Sachen nicht gekommen bin ^^
      Also mache ich erst Dateigröße, bei Kollision CRS32 der ersten 4096 Bytes, bei eine Kollision dort den SHA1.
      nein lass das mit CRC von 4k. Bei Anwendungen ist afaik in den ersten 4k der Block von wegen "This program cannot run in dos mode" das ist in jeder Anwendung gleich!
      Gilt auch für Bibliotheken.
      Hast du Cancel beim Durchsuchen der Dateien oder beim suchen der Duplikate gedrückt

      Duplikate.
      hast ja die Möglichkeit in der Result Liste nachzusehen ob es wirklich

      a) ich hab cancel, b) das Programm lief mit 4 GB Arbeitsspeicher nicht weiter
      ergo keine Resultlist
      Hm... Ich hab mal dein Programm und AllDup (was ich sonst immer nehme) den gleichen Ordner durchsuchen lassen, bei AllDup hatte ich folgende Suchmethode eingestellt: "Dateiinhalt (Byte für Byte)" mit der Option "Zuerst einen Datenblock am Ende der Dateien vergleichen. Blockgröße: 100000 Bytes".
      Ergebnis: AllDup: 8 Sekunden: 93 Duplikate
      Dein Programm: 29 Sekunden: 53 Duplikate
      Ich weiß nicht, was jetzt richtig von den beiden Ergebnissen ist...
      [Window Title]
      DuplicateFinder

      [Main Instruction]
      DuplicateFinder funktioniert nicht mehr

      [Content]
      Das Programm wird aufgrund eines Problems nicht richtig ausgeführt. Das Programm wird geschlossen und Sie werden benachrichtigt, wenn eine Lösung verfügbar ist.

      [Programm schließen]
      Für ein Mindestmaß an Rechtschreibung, Interpunktion und Majuskeln!
      Bei einem Klick auf suchen kommt bei mir: "DublicateFinder hat ein Problem festgestellt....etc"

      Ein Klick auf den Debug-Knopf liefert folgende Info:
      Unbehandelte Ausnahme (System.UnauthorizedAccessException) in DublicateFinder.exe [5516]

      Beim Debuggen der exe in Visual Studio 2008 kommt:
      UnauthorizedAccessException wurde nicht behandelt: Der Zugriff auf den Pfad "C:\Users\*ZENSIERT*\Anwendungsdaten" wurde verweigert.

      oder beim durchsuchen von ganz C:\:
      Der Zugriff auf den Pfad "C:\$Recycle.Bin\S-1-5-20" wurde verweigert.

      Offensichtlich wird deinem Programm der Zugang zu einigen Dateien verwehrt.
      Auch ein Start als Admin löst das Problem nicht. (auch wenn er mehr Dateien duchsucht als davor bis er abstürzt)

      Nun eine Gute Nachricht: In nicht geschüzten Bereichen, wie Unterverzeichnissen des Benutzerordners geht es einwandfrei!
      Dort war mir das Programm echt eine große Hilfe!

      Viel Erfolg noch!
      SᴛᴀʀGᴀᴛᴇ01
      bsp:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Imports AsyncCtpExtensions
      2. Imports System.Threading
      3. Imports System.Threading.Tasks
      4. Imports System.Security.Cryptography
      5. Public Class Form1
      6. Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
      7. End Sub
      8. Private Async Function GetFiles(ByVal p As String) As Task(Of Tuple(Of List(Of IO.FileInfo), Integer, Long))
      9. Dim path = p
      10. Dim a = Await Task.Factory.StartNew(Of List(Of IO.FileInfo))(New Func(Of List(Of IO.FileInfo))(Function()
      11. Return (From s In IO.Directory.GetFiles(path) Select New IO.FileInfo(s)).ToList
      12. End Function))
      13. Dim size As Long = (From fi In a Select fi.Length).Sum
      14. Return New Tuple(Of List(Of IO.FileInfo), Integer, Long)(a, a.Count, size)
      15. End Function
      16. Private Async Function GetHashes(ByVal l As List(Of IO.FileInfo), ByVal numtasks As Integer) As Task(Of Dictionary(Of String, String))
      17. Dim TaskList As New List(Of Task(Of Tuple(Of String, String)))
      18. Dim q As New Queue(Of IO.FileInfo)(l)
      19. ' fill initial tasks
      20. For i = 1 To numtasks
      21. If q.Count = 0 Then Exit For
      22. Dim s As String = q.Dequeue.FullName
      23. Debug.Print(s)
      24. Dim t As Task(Of Tuple(Of String, String)) = (New TaskFactory(Of Tuple(Of String, String))).StartNew(New Func(Of Tuple(Of String, String))(Function() As Tuple(Of String, String)
      25. Dim sha As New SHA256Managed
      26. Using fs As New IO.FileStream(s, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read, 1 << 20)
      27. Dim b() As Byte = sha.ComputeHash(fs)
      28. Dim sb As New System.Text.StringBuilder
      29. For Each bt In b
      30. sb.Append(bt.ToString("X2"))
      31. Next
      32. Return New Tuple(Of String, String)(s, sb.ToString)
      33. End Using
      34. End Function))
      35. TaskList.Add(t)
      36. Next
      37. Dim results As New Dictionary(Of String, String)
      38. Do
      39. Dim t As Task(Of Tuple(Of String, String)) = Await TaskEx.WhenAny(TaskList)
      40. results.Add(t.Result.Item1, t.Result.Item2)
      41. TaskList.Remove(t)
      42. If q.Count > 0 Then
      43. Dim s As String = q.Dequeue.FullName
      44. Debug.Print(s)
      45. TaskList.Add((New TaskFactory(Of Tuple(Of String, String))).StartNew(New Func(Of Tuple(Of String, String))(Function() As Tuple(Of String, String)
      46. Dim sha As New SHA256Managed
      47. Using fs As New IO.FileStream(s, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.Read, 1 << 20)
      48. Dim b() As Byte = sha.ComputeHash(fs)
      49. Dim sb As New System.Text.StringBuilder
      50. For Each bt In b
      51. sb.Append(bt.ToString("X2"))
      52. Next
      53. Return New Tuple(Of String, String)(s, sb.ToString)
      54. End Using
      55. End Function)))
      56. End If
      57. Loop Until TaskList.Count = 0
      58. Return results
      59. End Function
      60. Private Async Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
      61. Dim d As New FolderBrowserDialog
      62. If d.ShowDialog() = Windows.Forms.DialogResult.OK Then
      63. Dim tpl = Await GetFiles(d.SelectedPath)
      64. Debug.Print("Getting Hashes ...")
      65. Dim stp = Stopwatch.StartNew
      66. Dim lst = Await GetHashes(tpl.Item1, CInt(NumericUpDown1.Value))
      67. stp.Stop()
      68. For Each k In lst
      69. Debug.Print(k.Key & " : " & k.Value)
      70. Next
      71. Debug.Print(New String("-"c, 30))
      72. Dim bps As Long = (tpl.Item3 \ (1 << 20) \ stp.ElapsedMilliseconds) * 1000
      73. Debug.Print("Files: {0}, MB: {1}, MB/s: {2}", tpl.Item2, (tpl.Item3 >> 20), CDbl(tpl.Item3 \ (1 << 20)) / (CDbl(stp.ElapsedMilliseconds) / 1000.0#))
      74. End If
      75. End Sub
      76. End Class


      output (i7-2600 und je 8 Tasks):

      Quellcode

      1. Files: 187, MB: 37, MB/s: 17.5939134569662 | Bilder jpg
      2. Files: 17, MB: 3694, MB/s: 93.5237227201377 | Video mpg
      3. Files: 66, MB: 3438, MB/s: 79.0799309948246 | Video mpg
      4. Files: 498, MB: 12342, MB/s: 23.8714169664616 | Downloadverzeichnis
      5. Files: 51, MB: 45, MB/s: 25.1396648044693 | Bilder jpg


      Im Download-Verzeichnis sind überwiegend kleine und ein paar sehr große Dateien. Ansonsten sieht man, wie die Geschwindigkeit bei größeren Datein besser ist.

      Kannst du bei deinem Code auch rauswerfen, wie viel MB/s er verarbeitet?
      O.o oh cool danke ... aber das is FW 4.0 und ich möchte ja dass das Prog schnell benutzt werden kann und nicht erstmal ein FW heruntergeladen werden muss. Speziell habe ichs ja für ne Freundin geschrieben die unkoordiniertes Backup hat und eben auf ihrer Externen jede menge Daten doppelt. Ebenso hat sie nur langsames INet und sich da das FW runterladen was ja einige MBs sind möcht ich ihr dann nicht noch zumuten.

      Aber vlt. mache ich 2 Versionen, aber erstmal ein Code analysieren, LINQ und die neuen FW 4.0 Funktionen sind für mich ja noch ein Rätsel ^^