myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Gemeinschaft » .NET-Komponenten und C#-Snippets » CopyComponent zum Kopieren von Dateien mit Fortschritts-, Datendurchsatz-, und Restzeitberechnung
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

CopyComponent zum Kopieren von Dateien mit Fortschritts-, Datendurchsatz-, und Restzeitberechnung

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
t2t t2t ist männlich
myCSharp.de-Mitglied

Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017
Herkunft: Hamburg


t2t ist offline

CopyComponent zum Kopieren von Dateien mit Fortschritts-, Datendurchsatz-, und Restzeitberechnung

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Beschreibung:

Ich bin vor einiger Zeit über das Hindernis gestoßen, dass man im .NET Framework nur Dateien mit System.IO.File.Copy() als ein Ganzes kopieren kann. Möchte man nun z.B. eine große Datei kopieren, hat man keine Möglichkeit den Fortschritt des Kopiervorgangs auf der GUI, etwa durch eine Prozessbar, sichtbar zu machen.

Dieses Manko wollte ich beheben und hab mich dazu entschlossen eine Klasse zu schreiben, die Dateien binär kopiert und während dieses Vorgangs einen Fortschritt berechnet. Um das Ganze zu komplettieren habe ich auch gleich die Berechnung des Datendurchsatzes und der Restzeit des Kopiervorgangs mit eingebaut.

Um die Funktionalität nicht nur auf eine einzelne zu kopierende Datei zu beschränken, bietet die Klasse auch die Möglichkeit eine Liste von Dateien zu übergeben in Form einer System.Collections.Generic.List<string>, eines string[] Arrays oder eines System.IO.FileInfo[] Arrays. Die Klasse informiert dann während des Kopierens über den prozentualen Fortschritt der Dateiliste, der aktuell zu kopierenden Datei und bezogen auf die Datei die grad kopiert wird ebenfalls Fortschritt in Prozent, Datendurchsatz und Restzeit. Auf diese Weise ließe sich eine Kopier-Fortschritts-Ansicht erstellen, wie man es z.B. aus dem TotalCommander kennt. Eine Prozessbar für die gesamten zu kopierenden Dateien und eine für den Kopiervorgang der aktuellen Datei.

Die Klasse gibt alle Informationen über den Kopiervorgang per Events nach draußen, welche dann abonniert werden können. Der Komponente liegt eine Beispiel Applikation bei, die die CopyComponent in einem BackgroundWorker verwendet. Die wesentlichen Codestücke zur Verwendung habe ich noch mal hervorgehoben:

C#-Code:
// Instanz der BinaryCopiers
BinaryCopy bCopy = new BinaryCopy();

private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
      // Event des BinaryCopiers registrieren
     bCopy.BinaryCopyEvent += new BinaryCopyEventHandler(bCopy_BinaryCopyEvent);
     // Kopie der Datei starten
     bCopy.Copy(tbSource.Text, tbDestination.Text, true);
}

void bCopy_BinaryCopyEvent(object sender, BinaryCopyEventArgs e)
{
     // Auf das BinaryCopy Event reagieren und beim BGW das ProgressChanged Event auslösen und die BinaryCopyEventArgs übergeben
      backgroundWorker.ReportProgress(e.Percent, (object)e);
}

private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
       // EventArgs abfragen
       BinaryCopyEventArgs binaryArgs = (e.UserState as BinaryCopyEventArgs);
       // Prozessbar aktualisiern
       tsProgressBar.Value = e.ProgressPercentage;
       // Datendurchsatz in einem Label anzeigen
       tsslRate.Text = binaryArgs.KbPSec.ToString("N").Substring(0, binaryArgs.KbPSec.ToString("N").Length - 3) + " Kb/sec";
       // Restzeit in einem Label anzeigen
       tsslRemaning.Text = binaryArgs.Remaning.ToString();
}

Die Klasse mit der Beispielanwendung befindet sich im Anhang. Für Korrekturen (auch am Stil) und Verbesserungsvorschläge bin ich natürlich offen.

UPDATE vom 11.10.2010 (Datei-Downloads vor Update: 229):
- Verbesserungsvorschläge von Abt übernommen (siehe Postings weiter unten)
- Eine Methode zum kopieren ganzer Ordner samt Inhalt hinzugefügt

UPDATE vom 26.03.2014 (Datei-Downloads vor Update: 459):
- Verbessertes kopieren von Ordnern, welches nun auch per Event über den Fortschritt des kopierens eines ganzen Ordners informiert.
- Sample App auf die Veränderung angepasst

Schlagwörter: kopieren, Daten kopieren, Datei kopieren, Dateien kopieren, Restzeit, Datendurchsatz, Prozessfortschritt


Dateianhang:
unknown CopyComponent_v1.2.rar (146,14 KB, 503 mal heruntergeladen)

Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von t2t am 27.03.2014 12:53.

26.11.2009 18:59 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
t2t t2t ist männlich
myCSharp.de-Mitglied

Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017
Herkunft: Hamburg

Themenstarter Thema begonnen von t2t

t2t ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hier noch ein Screen der Beispielanwendung:

t2t hat dieses Bild (verkleinerte Version) angehängt:
copySample2.jpg
Volle Bildgröße

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von t2t am 26.03.2014 10:31.

26.11.2009 19:00 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 8 Monate.
bbb
myCSharp.de-Mitglied

Dabei seit: 31.03.2009
Beiträge: 72


bbb ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Vielen Dank, sowas hatte ich gesucht und konnte es gut in meinem Projekt verwenden!
08.08.2010 12:56 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegt mehr als ein Monat.
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hi,

erst mal danke für dein Projekt!

C#-Code:
if (newFileName != string.Empty)
            {
                if (File.Exists(destination + @"\" + newFileName) && !overwrite)
                    throw new IOException("Die im Zielverzeichnis vorhandene Zieldatei kann nicht überschrieben werden");
            }
            else
            {
                if (File.Exists(destination + @"\" + srcFileInfo.Name) && !overwrite)
                    throw new IOException("Die im Zielverzeichnis vorhandene Zieldatei kann nicht überschrieben werden");
            }

habe ich bei mir in

C#-Code:
            if ( newFileName != string.Empty )
            {
                if ( File.Exists( Path.Combine( destination, newFileName ) ) && !overwrite )
                    throw new IOException( "Die im Zielverzeichnis vorhandene Zieldatei kann nicht überschrieben werden" );
            }
            else
            {
                if ( File.Exists( Path.Combine( destination, srcFileInfo.Name ) )&& !overwrite )
                    throw new IOException( "Die im Zielverzeichnis vorhandene Zieldatei kann nicht überschrieben werden" );
            }

ändern müssen, da ich bei mir keine fixen Pfadkomponenten im Quelltext stehen haben darf/möchte und stattdessen auf Path.Combine() setze.

Bei der Berechnung der kbPSec könnte es zu einem Umrechnungsfehler kommen, wenn bytesReceived und sec beides Ganzzahlen sind, kbPSec aber ein Double darstellt - erklärt jedenfalls die Anzeige bei mir die mitten drin plötzlich 0.0 anzeigt.

C#-Code:
                if ( sec > 0 )
                    kbPSec = bytesReceived / sec;

in

C#-Code:
                if ( sec > 0 )
                    kbPSec = 1.0 * bytesReceived / sec;

Weiterhin hab ich bei mir den Event BinaryCopyEventArgs um das Argument bytesReceived erweitert, sodass ich bei einer Vielzahl von Copy-Prozessen den Gesamtfortschritt haargenau anzeigen kann.

Aber klappt ansonsten prima Daumen hoch
22.09.2010 11:23 Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Also ich hab mal die Hauptfunktion überarbeitet: smile

C#-Code:
public void Copy( string source, string destination, string newFileName, bool overwrite )
{
    FileInfo srcFileInfo = new FileInfo( source );

    // Verify that the source file exists
    if ( !srcFileInfo.Exists )
        throw new IOException( "Source file does not exist" );

    // Verify that the destionation folder exists
    if ( !Directory.Exists( destination ) )
        throw new IOException( "Target directory does not exist." );

    // Verify that the given new file name does not exist ( if overwrite is forbidden )
    if ( !string.IsNullOrEmpty( newFileName ) && File.Exists( Path.Combine( destination, newFileName ) ) && !overwrite )
        throw new IOException( "The target file exists and can not be overwritten." );

    // Verify that the source file does not exist ( if overwrite is forbidden )
    if ( File.Exists( Path.Combine( destination, srcFileInfo.Name ) ) && !overwrite )
        throw new IOException( "The target file exists and can not be overwritten." );

    // Standard target file
    FileInfo currentTargetFileInfo = new FileInfo( Path.Combine( destination, srcFileInfo.Name ) );

    // Change target file to given new file name
    if ( !string.IsNullOrEmpty( newFileName ) )
        currentTargetFileInfo = new FileInfo( Path.Combine( destination, newFileName ) );

    // Creating Streams
    FileStream destStream = new FileStream( currentTargetFileInfo.FullName, FileMode.Create, FileAccess.Write );
    FileStream srcStream = new FileStream( source, FileMode.Open, FileAccess.Read );

    // Standard buffer
    byte[ ] streamBuffer = new byte[ 32768 ];

    // Increase buffer
    if ( srcFileInfo.Length < 32768 )
        streamBuffer = new byte[ srcFileInfo.Length ];


    const int offset = 0;
    int remainSec = 0;
    int remain = streamBuffer.Length;
    long iMax = srcFileInfo.Length;
    long bytesReceived = 0;
    double kbPSec = 0;

    DateTime start = DateTime.Now;

    while ( srcStream.Read( streamBuffer, offset, remain ) > 0 )
    {
        // Bufferinhalt in die Zieldatei schreiben
        destStream.Write( streamBuffer, offset, remain );

        // Prozentualen Fortschritt berechnen
        double percent = 1.0 * ( bytesReceived * 100 ) / iMax;

        // Datendurchsatz berechnen (Empfangene Bytes / verstrichene Zeit)
        bytesReceived += streamBuffer.Length;
        int sec = ( int ) Math.Round( DateTime.Now.Subtract( start ).TotalMilliseconds, MidpointRounding.AwayFromZero );

        if ( sec > 0 )
            kbPSec = 1.0 * bytesReceived / sec;

        // Restzeit des Kopiervorgangs berechnen (verbleibende Bytes / Datendurchsatz)
        if ( kbPSec > 0 )
        {
            remainSec = ( int ) Math.Round( ( ( ( ( iMax - bytesReceived ) / kbPSec ) / 1000 ) ), MidpointRounding.AwayFromZero );
        }
        TimeSpan remaning = new TimeSpan( 0, 0, remainSec );

        // Kopierevent feuern
        OnBinaryCopy( new BinaryCopyEventArgs( bytesReceived, percent, kbPSec, remaning ) );

        // StreamBuffer ggf. anpassen, um keine Nullen in die Datei zu schreiben
        if ( ( iMax - bytesReceived ) >= 32768 ) continue;

        streamBuffer = new byte[ iMax - bytesReceived ];
        remain = streamBuffer.Length;
    }

    destStream.Close( );
    srcStream.Close( );
}

Und den dazugehörigen Event vereinfacht:

C#-Code:
public class BinaryCopyEventArgs : EventArgs
{
    public BinaryCopyEventArgs(long bytesReceived, double percent, double kbPSec, TimeSpan remaning)
    {
        this.BytesReceived = bytesReceived;
        this.Percent = percent;
        this.KbPSec = kbPSec;
        this.Remaning = remaning;
    }

    /// <summary>
    /// Fortschrittsangabe des Kopiervorgangs in Prozent
    /// </summary>
    public double Percent { private set; get; }

    /// <summary>
    /// Datendurchsatz des Kopiervorgangs in KB pro Sekunde
    /// </summary>
    public double KbPSec{ private set; get; }

    /// <summary>
    /// Verbleibende Zeitspanne des aktuellen Kopiervorgangs
    /// </summary>
    public TimeSpan Remaning{ private set; get; }

    /// <summary>
    /// Gets or sets the bytes received.
    /// </summary>
    /// <value>The bytes received.</value>
    public long BytesReceived { private set; get; }
}

Ich hoff' das geht so in Ordnung Augenzwinkern
22.09.2010 12:52 Beiträge des Benutzers | zu Buddylist hinzufügen
t2t t2t ist männlich
myCSharp.de-Mitglied

Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017
Herkunft: Hamburg

Themenstarter Thema begonnen von t2t

t2t ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hey Abt,

vielen Dank für deine Anmerkungen und Verbesserungsvorschläge. Ich habe die Snipp überarbeitet und im ersten Post aktualisiert. Zusätzlich bietet die Komponente nun noch eine Methode zum kopieren ganzer Ordner samt Unterordner und Dateien.
11.10.2010 18:37 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hi,

hier ist nochmal ein Fehler:

C#-Code:
OnFileListCopy(new FileListCopyEventArgs((runner * 100) / sourceFiles.Length, sourceFile.Name));

Sollte 100.0 sein (possible loss of fraction)

Okay, sehe grade, dass das ja nur den "runner" betrifft und somit egal ist

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Abt am 25.10.2010 09:18.

25.10.2010 08:56 Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 3 Jahre.
t2t t2t ist männlich
myCSharp.de-Mitglied

Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017
Herkunft: Hamburg

Themenstarter Thema begonnen von t2t

t2t ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Es gab noch mal ein kleines Update auf Version 1.2 siehe Beschreibung oben.
26.03.2014 10:32 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 2 Monate.
digicorder
myCSharp.de-Mitglied

Dabei seit: 10.06.2014
Beiträge: 1


digicorder ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

das Tool ist nicht schlecht, jedoch werden immer alle Dateien kopiert die in der Quelle vorhanden sind. gibt es eine möglichkeit vorher zu vergleichen was im Ziel vorhanden ist bzw. älter ist, da nur neue und fehlende Dateien kopiert werden sollen?

Danke für die Antwort im Vorraus
14.06.2014 10:19 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Palladin007 Palladin007 ist männlich
myCSharp.de-Mitglied

avatar-4140.png


Dabei seit: 03.02.2012
Beiträge: 1.379
Entwicklungsumgebung: Visual Studio Preview
Herkunft: NRW


Palladin007 ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Das geht über den Aufgabenbereich der Klasse hinaus, die soll schließlich nur kopieren und dabei genau über den aktuellen Stand informieren.

Wenn du die Dateien filtern möchtest, dann musst du das vorher tun, also der Klasse schon gefiltert übergeben.

PS:

Mir fällt auch gerade auf, dass das Thema schon ewig alt ist.
Ich denke nicht, dass sich da der Thread-Starter noch darum kümmert.

Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Palladin007 am 14.06.2014 11:38.

14.06.2014 10:58 Beiträge des Benutzers | zu Buddylist hinzufügen
Abt
myCSharp.de-Team

avatar-4119.png


Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW


Abt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

...und mittlerweile hab ich  QuickIO.NET - Performante Dateioperationen veröffentlich, mit dem so etwas sehr einfach realisierbar ist.
Was aber genau "gleich" bei Dateien bedeutet verstehen viele anders:

Einfach zwei Listen mit den Dateien aus Quelle und Ziel erstellen.
Beide nach eigenen Kriterien vergleichen.
Aktualisierte / Neue Dateien kopiere.
-> Fertig.
15.06.2014 13:22 Beiträge des Benutzers | zu Buddylist hinzufügen
t2t t2t ist männlich
myCSharp.de-Mitglied

Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017
Herkunft: Hamburg

Themenstarter Thema begonnen von t2t

t2t ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Diese gewünschte Funktionalität wird in der Tat nicht unterstützt. Da aber die Sourcen vorhanden sind, kann man sich das leicht nach-implementieren. Oder wie von den Vorrednern erwähnt sich die Listen vorbereiten und dann erst zum kopieren schicken.

Der Fokus dieser Snippet liegt auf der einfachen Einbindung ins eigene Projekt und der Lösung eines konkreten Problems. Wer ein mächtigeres Kopier-Werkzeug mit deutlich mehr Funktionalität haben will, der sollte sich bei Abt's QuickIO bedienen.

@digicorder Solltest du dir die Komponente erweitern, dann kannst dir mir deine Änderungen gerne schicken und ich aktualisiere den Thread damit.
16.06.2014 11:12 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 11 Jahre.
Der letzte Beitrag ist älter als 6 Jahre.
Antwort erstellen


© Copyright 2003-2021 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 24.01.2021 16:59