Tatsächliche Dateigröße ermitteln

  • VB.NET

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von Astharey.

    Tatsächliche Dateigröße ermitteln

    Guten Morgen,

    ich habe einen Kopiervorgang erstellt, bei dem Ordner und Dateien von A nach B kopiert werden.

    VB.NET-Quellcode

    1. Function GetFileLength(ByVal filename As String) As Long
    2. Dim retval As Long
    3. Try
    4. Dim fi As New System.IO.FileInfo(filename)
    5. retval = fi.Length
    6. Catch ex As System.IO.FileNotFoundException
    7. ' If a file is no longer present,
    8. ' just return zero bytes.
    9. retval = 0
    10. End Try
    11. Return retval
    12. End Function
    13. Private Sub testtimer_Tick(sender As System.Object, e As System.EventArgs) Handles testtimer.Tick
    14. Dim root As String = Zielverzeichnis.Text
    15. Dim fileList = My.Computer.FileSystem.GetFiles _
    16. (root, FileIO.SearchOption.SearchAllSubDirectories, "*.*")
    17. Dim fileQuery = From file In fileList _
    18. Select GetFileLength(file)
    19. Dim fileLengths = fileQuery.ToArray()
    20. Dim totalBytes = Aggregate aFile In fileLengths Into Sum()
    21. text_label.Text = "Es sind bereits " & totalBytes & " Bytes kopiert " & _
    22. fileList.Count & " Dateien im Verzeichnis " & root
    23. End Sub


    Hiermit soll der Fortschritt in einem Label angezeigt wurden. Bei den zu kopierenden Dateien wird allerdings nicht die tatsächliche Dateigröße ermittelt, sondern es wird direkt die Dateigröße ausgegeben, die eben am Ende herauskommen sollte.

    Zur genaueren Erläuterung: Angenommen, kopiert würde eine sehr große Datei von 500.000.000 Bytes. Per Timer würde dann im Interval von ein paar Millisekunden ständig die Größe aller Dateien im Zielverzeichnis ermittelt werden (das macht der Code oben). Allerdings wird dann nicht die "derzeitige" Dateigröße im Zielverzeichnis ausgegeben, sondern es werden direkt die 500.000.000 Bytes zum vorherigen Wert draufgerechnet, also die "Soll-"Dateigröße aus dem Quellverzeichnis.

    Ich hoffe, Ihr versteht was ich meine. Würde mich über Antworten freuen.

    Beste Grüße

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

    Beim Kopieren wird im Zielverzeichnis zunächst ein leerer Dateirahmen mit der Zielgröße der Dateo angelegt.
    Der Platz wird also schon mal reserviert.

    Wenn du die bereits kopierten Daten ermitteln willst, musst du die Informationen des Kopierprogramms heranziehen.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Hi, Danke für die Antwort. Okay, das erklärt zumindest warum so gearbeitet wird.

    Die Dateien werden ganz normal über einen BackgroundWorker kopiert, per IO.File.Copy(). Hab nur keinen blassen Schimmer, wie ich das jetzt umsetzen soll. :wacko:

    Gruß
    File.Copy lässt dich meines Wissens nicht am Kopierfortschritt teilhaben.

    Der WinAPI-Funktion CopyFileEx kannst du einen Delegaten für die Fortschrittsanzeige mitgeben.
    Vielleicht gibt es sogar eine .Net-Funktion, die das auch kann, weiß ich jetzt aber nicht auswendig.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Danke. Damit würde es vermutlich funktionieren, muss es eben nur in 'ne For-Schleife packen, da ja Dateien aus Ordnern kopiert werden sollen.

    Was ich an der Sache doof finde: Das Erstelldatum der Datei verloren geht, sie wir ja grundsätzlich neu geschrieben. Gibt's hierfür 'ne Lösung?

    Was mich interessieren würde: Wie arbeitet die ProgressBar wenn man mit Windows eine Datei bzw. einen Ordner kopiert? Das wäre genau das, was ich bräuchte.

    Der WinAPI-Funktion CopyFileEx kannst du einen Delegaten für die Fortschrittsanzeige mitgeben.

    Vielleicht gibt es sogar eine .Net-Funktion, die das auch kann, weiß ich jetzt aber nicht auswendig.
    Könntest du mir das mal vielleicht näher erläutern? Das mit dem Fortschritt klingt ganz gut, da auch noch 'ne ProgressBar mit eingebaut wird, neben dem Zähler für die kopierten Dateien.


    Gruß

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

    Astharey schrieb:

    Gibt's hierfür 'ne Lösung?
    Klar doch:

    VB.NET-Quellcode

    1. Dim fi As New System.IO.FileInfo("C:\Temp\xxx.jpg")
    2. fi.CreationTime = New DateTime(2000, 1, 1, 0, 0, 0)
    Bilder
    • Creation.jpg

      48,06 kB, 426×603, 182 mal angesehen
    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!
    Für CopyFileEx gibt's hier ein Beispiel.
    Du solltest allerdings schon grundsätzlich verstehen, wie Delegaten (Callbacks) funktionieren.

    Notfalls ziehst du dir diese Grundlagen rein:
    download.microsoft.com/downloa…ting_vb_net_delegates.pdf
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --
    Oha, das klingt für 'n Anfänger aber ganz schön schwierig. Mal schauen, eigentlich bin ich eher der Typ, der schnell Ergebnisse sehen will. :D

    RodFromGermany schrieb:

    Gibt's hierfür 'ne Lösung?
    Klar doch:

    Dim fi As New System.IO.FileInfo("C:\Temp\xxx.jpg")
    fi.CreationTime = New DateTime(2000, 1, 1, 0, 0, 0)

    Dankeschön, sieht gut aus. Gibt es auch die Möglichkeit, die "CreationTime" von der Quelldatei zu übernehmen? In 'ner For-Schleife lässt sich das für jede einzelne Datei nämlich schlecht unterbringen.

    Gruß

    Astharey schrieb:

    Gibt es auch die Möglichkeit, die "CreationTime" von der Quelldatei zu übernehmen?
    Nix einfacher als das:

    VB.NET-Quellcode

    1. Dim fi As New System.IO.FileInfo("C:\Temp\xxx.jpg")
    2. Dim ct As DateTime = fi.CreationTime
    3. 'fi.CreationTime = New DateTime(2000, 1, 1, 0, 0, 0)
    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!
    Danke für deine Hilfe.

    Hab' ein kleines Problem: Hab die Funktion soweit umgeschrieben, aber der FileStream scheint nicht mit 'ner CD zu klappen. Es sollen genauer gesagt Dateien von einer CD kopiert werden.

    VB.NET-Quellcode

    1. Dim total As Long = 0
    2. Dim buffer(1024) As Byte
    3. Dim current As Long = 0
    4. For Each Datei In System.IO.Directory.GetFiles(sourcedir_path.Text)
    5. Dim Datei2 As String = Path.GetFileName(Datei)
    6. Dim Quelldatei As FileStream = New FileStream(Datei, FileMode.Open)
    7. Dim Zieldatei As FileStream = New FileStream(targetdir_path.Text & "\" & Datei2, FileMode.Create)
    8. Do
    9. Dim read As Integer = Quelldatei.Read(buffer, 0, buffer.Length)
    10. Zieldatei.Write(buffer, 0, read)
    11. current += read
    12. Application.DoEvents()
    13. Loop While (total <> current)
    14. Dim fi As New System.IO.FileInfo(Datei2)
    15. Dim ct As DateTime = fi.CreationTime
    16. Zieldatei.Close()
    17. Quelldatei.Close()
    18. Next


    Scheitert schon am Zugriff auf die Quelldatei, die sich auf einer CD befindet. Gibt's 'ne Alternative dafür?

    Gruß

    Astharey schrieb:

    Es sollen genauer gesagt Dateien von einer CD kopiert werden.
    Was für Dateien?
    Ist die CD irgendwie kopiergeschützt?
    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!
    Nee, kein Kopierschutz, muss einfach mit der CD zusammenhängen. Sind Dateien eines PC-Spiels, nichts besonderes. Schreibe einen neuen Installer für ein altes PC-Spiel, dessen Installer nicht mehr unter Windows funktioniert inkl. gepatchter Dateien.

    Gruß
    Warum kopierst Du die Dateien nicht einfach im Explorer?
    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!
    Danke für deine Antwort, allerdings konnte ich das Problem in der Zwischenzeit selbst lösen. ProgressBar, Fortschrittsanzeige im Label und der Kopiervorgang funktionieren jetzt.

    So funktioniert's:

    VB.NET-Quellcode

    1. Try
    2. For Each Eingabedatei In My.Computer.FileSystem.GetFiles(sourcedir_path.Text, FileIO.SearchOption.SearchTopLevelOnly)
    3. Dim Ausgabedatei As String = Path.GetFileName(Eingabedatei)
    4. Dim Quelldateien As FileStream = New FileStream(Eingabedatei, FileMode.Open, FileAccess.Read, FileShare.Read)
    5. Dim Zieldateien As FileStream = New FileStream(targetdir_path.Text & "\" & Ausgabedatei, FileMode.Create)
    6. Dim total As Long = Quelldateien.Length
    7. Dim current As Long = 0
    8. Dim buffer(2048) As Byte
    9. Do
    10. Dim read As Integer = Quelldateien.Read(buffer, 0, buffer.Length)
    11. Zieldateien.Write(buffer, 0, read)
    12. current += read
    13. SetLabelText(progress_txt, "Current file: " & Ausgabedatei.ToString)
    14. Application.DoEvents()
    15. Loop While (total <> current)
    16. Dim Datum1 As New System.IO.FileInfo(Eingabedatei)
    17. Dim Datum2 As New System.IO.FileInfo(targetdir_path.Text & "\" & Ausgabedatei)
    18. Quelldateien.Close()
    19. Zieldateien.Close()
    20. Datum2.LastWriteTime = Datum1.LastWriteTime
    21. Application.DoEvents()
    22. Next


    Zur ProgressBar: Einfach einen Timer erstellen, der alle Bytes in einem Ordner liest und diesen Wert als ProgressBar.Value festlegen. ProgressBar.Maximum entspricht dem oder den Quellpfad(en).

    Gruß