Sporadische Fehler beim File umbenennen

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

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Fakiz.

    Sporadische Fehler beim File umbenennen

    Moin moin

    Ich habe mit dieser Class / Function beim umbenennen einige "Sporadische" Fehler.
    Je nach Anzahl der Dateien in einem Verzeichnis bekomme ich die Meldung:

    ​Datei kann nicht erstellt werden, wenn sie schon vorhanden ist.

    Die Anzahl der Dateien wo dieser Fehler auftritt ist nicht fest, mal sind es 2 mal 4 usw... Ich habe dann versucht es mit eine kleinen "Wartezeit" bzgl der Task zu kompensieren, um zu testen ob es da Probleme gibt. Allerdings funktioniert das nur sehr begrenzt und so denke ich nicht die beste Lösung ist.

    Bei ​Await Task.Delay(100) passt es z.B. wenn in dem Verzeichnis nicht mehr als 200 Dateien sind. In einem anderen Testverzeichnis mit 1500 Dateien, passt ein Wert von 550 schon nicht mehr.

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Public Class FileRenamer
    2. Private renamedFilesField As New List(Of FileInfo)()
    3. Public Property RenamedFiles As List(Of FileInfo)
    4. Get
    5. Return renamedFilesField
    6. End Get
    7. Private Set(ByVal value As List(Of FileInfo))
    8. renamedFilesField = value
    9. End Set
    10. End Property
    11. Public Property NewFileName As String
    12. Public Property RenamedFileName As String
    13. Public Property SuffixCounter As Integer = 0
    14. Public Property SuffixStartValue As Integer = 0
    15. Public Property SuffixLetter As String
    16. Public Property CountRenamedFiles As Integer
    17. Public Property DateofChange As Boolean
    18. Public Event ErrorOccurred(ByVal errorMessage As String)
    19. Public Event RenamedFileCountUpdated(ByVal count As Integer)
    20. Public Event RenamedFilesUpdated(ByVal files As List(Of FileInfo))
    21. Public ReadOnly Property RenamedFileInfo As List(Of FileInfo)
    22. Get
    23. Return renamedFilesField
    24. End Get
    25. End Property
    26. Public Async Function RenameFiles(ByVal selectedDirectory As String, ByVal files As List(Of String)) As Task
    27. Debug.WriteLine(selectedDirectory)
    28. RenamedFiles.Clear()
    29. CountRenamedFiles = 0
    30. Dim tasks As List(Of Task) = files.Select(Function(file) Task.Run(Function() RenameFileAsync(selectedDirectory, file))).ToList()
    31. Await Task.WhenAll(tasks)
    32. RaiseEvent RenamedFileCountUpdated(CountRenamedFiles)
    33. RaiseEvent RenamedFilesUpdated(RenamedFiles)
    34. End Function
    35. Private Async Function RenameFileAsync(ByVal selectedDirectory As String, ByVal file As String) As Task
    36. Dim extension As String = Path.GetExtension(file)
    37. Dim oldName As String = Path.Combine(selectedDirectory, file)
    38. Dim renamedFileName As String = Path.Combine(selectedDirectory, NewFileName & "_" & GenerateNewSuffix() & extension.ToLower())
    39. Dim fileExists As Boolean = System.IO.File.Exists(renamedFileName)
    40. While fileExists
    41. CountRenamedFiles += 1
    42. renamedFileName = Path.Combine(selectedDirectory, NewFileName & "_" & GenerateNewSuffix() & extension.ToLower())
    43. fileExists = System.IO.File.Exists(renamedFileName)
    44. Await Task.Delay(100) ' Kurze Wartezeit zum Testen!!
    45. End While
    46. Try
    47. Dim fileInfo As New FileInfo(oldName)
    48. If DateofChange Then
    49. fileInfo.LastWriteTime = DateTime.Now
    50. End If
    51. Await Task.Run(Sub()
    52. Try
    53. fileInfo.MoveTo(renamedFileName)
    54. RenamedFiles.Add(fileInfo)
    55. CountRenamedFiles += 1
    56. Catch moveException As Exception
    57. DebugWriteLine("Fehler beim Umbenennen der Datei: " & file & ". Fehler: " & moveException.Message)
    58. ' RaiseEvent ErrorOccurred("Fehler beim Umbenennen der Datei: " & file & ". Fehler: " & moveException.Message)
    59. End Try
    60. End Sub)
    61. Catch ex As Exception
    62. DebugWriteLine("Fehler beim Umbenennen der Datei: " & file & ". Fehler: " & ex.Message)
    63. ' RaiseEvent ErrorOccurred("Fehler beim Umbenennen der Datei: " & file & ". Fehler: " & ex.Message)
    64. End Try
    65. End Function
    66. Private Function GenerateNewSuffix() As String
    67. Dim suffix As String = ""
    68. If Not String.IsNullOrEmpty(SuffixLetter) Then
    69. suffix = SuffixLetter & "_"
    70. End If
    71. Dim counterString As String = SuffixCounter.ToString().PadLeft(4, "0"c)
    72. suffix &= SuffixStartValue.ToString() & SuffixCounter.ToString("D4")
    73. SuffixCounter += 1
    74. Return suffix
    75. End Function
    76. End Class

    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Sind die Namen von oldname und renamedFileName denn immer unterschiedlich?
    Aus dem "Umbenennen" schließe ich, dass du nicht wirklich verschiebst, sondern im gleichen Pfad bleibst. Wenn der Name sich also nicht ändert, dann kann das nicht funktionieren.

    Aber MoveTo kann wohl auch überschreiben: Probier mal FileInfo.MoveTo(renamedFileName, True)

    Übrigens eine interessante Konstellation wenn das klappt, da frisst der die Datei auf und schreibt sie dann wieder hin, wie würde das wohl laufen wenn die Datei sehr groß wird?

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

    Spekulatius: Die Generierung vermeintlich eindeutiger neuer Dateinamen erfolgt für alle Dateien nebenläufig, also vermeintlich gleichzeitig. Und zwar bevor die Dateien wirklich umbenannt wurden. Da kann es wahrscheinlich passieren, dass Dateien den gleichen Namen erhalten.

    ##########

    Das ganze Vorgehen kommt mir aber eh kritisch vor. Hattest Du schon mal getestet, wie groß der Zeitunterschied ist, wenn Du alle Dateien in einem Task nacheinander umbenennst - im Vergleich zu Deiner "alle Dateien gleichzeitig"-Variante? Die nacheinander-Variante sollte nämlich das hiesige Problem nicht aufweisen.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

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

    @Haudruferzappeltnoch
    Wenn der Name sich also nicht ändert, dann kann das nicht funktionieren.

    Naja manchmal klappt das umbenennen einwandfrei und manchmal eben bei einigen Dateien eben nicht. Auch die Reihenfolge welche gerade einen Fehler produziert ist nicht festzumachen.
    Mal Datei 2 dann wieder Datei 256 usw... eben schlecht nachzuprüfen. Das einzige was ich bis jetzt festmachen konnte:
    Je mehr Dateien in einem Verzeichnis, desto mehr produzieren auch den Fehler.

    @VaporiZed
    neuer Dateinamen erfolgt für alle Dateien nebenläufig, also vermeintlich gleichzeitig.

    Also muss ich diese Function:Private Async Function RenameFileAsync(ByVal selectedDirectory As String, ByVal file As String) As Task irgendwie anders schreiben? Nur wie...?
    Dachte in der While Schleife wird eine Datei nach der anderen umbenannt? Hatte zwischenzeitlich schon mit einem temporären Verzeichnis versucht zu arbeiten. Hat leider nicht so funktioniert wie ich dachte.
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:
    Statt es »irgendwie anders schreiben« zu wollen, solltest Du den Weg von der Startlinie aus anders gehen. Wie gesagt: Erstmal testweise, um zu sehen, ob es relevante Geschwindigkeitsunterschiede für Dich gibt. Also erstmal Projekt-Backup machen, 1000 umzubenennende Testdateien in ein Testverzeichnis packen und damit dann testen. Der alternative Weg sollte sein:
    1. Alles ohne Async/Await schreiben, sodass alles eben nicht nebenläufig vonstatten geht.
    2. Eine Methode erstellen, welche den Umbenennungsvorgang ohne GUI-Änderungen durchläuft.
    3. Diese Methode nebenläufig aufrufen.
    Beispiel in Pseudocode:

    Quellcode

    1. Sub Async Klick_Des_Umbenennungsstartknopfs
    2. SammleAlleRelevantenDateiinformationen()
    3. Await Threadings.Tasks.Task.Run() FühreUmbenennungAllerDateienDurch())
    4. BerichteErgebnisseAnsGUI()
    5. End Sub

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Amelie schrieb:

    Je mehr Dateien in einem Verzeichnis, desto mehr produzieren auch den Fehler
    Du hast bisher nicht geschrieben wie der neue Name festgelegt wird.
    An sich kann es auch immer noch sein, dass der alte Name bestehen bleibt, dass müsste statistisch gesehen mit mehr Dateien auch öfter vorkommen.

    Das mit Async Await habe ich noch gar nicht bemerkt. Da könnte die Suffix Methode vielleicht nicht hinterherkommen. Die schreibt dann ein früheres Suffix nochmal hin.
    Habe mal asynchron versucht zu zählen, das ging auch für größere Zahlen immer mehr in die Hose.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Haudruferzappeltnoch“ ()

    Es könnte ein reines Windows Problem sein. Ich hatte in der Vergangenheit Probleme wenn ein Dateiname mit einem Leerzeichen anfing und ich es entfernen wollte. Solche Dateinamen habe ich öfter im Zusammenhang mit Youtube und dem von mir benutzten Tool heise.de/download/product/h2rename-67112.
    Aktuelles Projekt: Z80 Disassembler für Schneider/Amstrad CPC :love:
    Das/ein Problem sehe ich in der While-Schleife. Zum einen macht es wenig Sinn nach dem du geprüft hast ob die Datei existiert zu warten zum anderen können alle Threads die Variable CountRenamedFiles ändern. Du könntest die While-Schleife in ein SyncLock (glaub das heißt bei VB so) packen. Das könnte aber dann zu Performance-Einbußen führen. Sollte aber dein Problem beheben.