|
» myCSharp.de Diskussionsforum |
|
|
|
Autor
 |
|
t2t
myCSharp.de-Mitglied
Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017 Herkunft: Hamburg
|
|
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: |
BinaryCopy bCopy = new BinaryCopy();
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
bCopy.BinaryCopyEvent += new BinaryCopyEventHandler(bCopy_BinaryCopyEvent);
bCopy.Copy(tbSource.Text, tbDestination.Text, true);
}
void bCopy_BinaryCopyEvent(object sender, BinaryCopyEventArgs e)
{
backgroundWorker.ReportProgress(e.Percent, (object)e);
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BinaryCopyEventArgs binaryArgs = (e.UserState as BinaryCopyEventArgs);
tsProgressBar.Value = e.ProgressPercentage;
tsslRate.Text = binaryArgs.KbPSec.ToString("N").Substring(0, binaryArgs.KbPSec.ToString("N").Length - 3) + " Kb/sec";
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
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
myCSharp.de-Mitglied
Dabei seit: 22.10.2007
Beiträge: 413
Entwicklungsumgebung: VS2017 Herkunft: Hamburg
Themenstarter
|
|
Hier noch ein Screen der Beispielanwendung:
t2t hat dieses Bild (verkleinerte Version) angehängt:
 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
|
|
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
Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW
|
|
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
|
|
22.09.2010 11:23
|
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Abt
myCSharp.de-Team
Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW
|
|
Also ich hab mal die Hauptfunktion überarbeitet:
C#-Code: |
public void Copy( string source, string destination, string newFileName, bool overwrite )
{
FileInfo srcFileInfo = new FileInfo( source );
if ( !srcFileInfo.Exists )
throw new IOException( "Source file does not exist" );
if ( !Directory.Exists( destination ) )
throw new IOException( "Target directory does not exist." );
if ( !string.IsNullOrEmpty( newFileName ) && File.Exists( Path.Combine( destination, newFileName ) ) && !overwrite )
throw new IOException( "The target file exists and can not be overwritten." );
if ( File.Exists( Path.Combine( destination, srcFileInfo.Name ) ) && !overwrite )
throw new IOException( "The target file exists and can not be overwritten." );
FileInfo currentTargetFileInfo = new FileInfo( Path.Combine( destination, srcFileInfo.Name ) );
if ( !string.IsNullOrEmpty( newFileName ) )
currentTargetFileInfo = new FileInfo( Path.Combine( destination, newFileName ) );
FileStream destStream = new FileStream( currentTargetFileInfo.FullName, FileMode.Create, FileAccess.Write );
FileStream srcStream = new FileStream( source, FileMode.Open, FileAccess.Read );
byte[ ] streamBuffer = new byte[ 32768 ];
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 )
{
destStream.Write( streamBuffer, offset, remain );
double percent = 1.0 * ( bytesReceived * 100 ) / iMax;
bytesReceived += streamBuffer.Length;
int sec = ( int ) Math.Round( DateTime.Now.Subtract( start ).TotalMilliseconds, MidpointRounding.AwayFromZero );
if ( sec > 0 )
kbPSec = 1.0 * bytesReceived / sec;
if ( kbPSec > 0 )
{
remainSec = ( int ) Math.Round( ( ( ( ( iMax - bytesReceived ) / kbPSec ) / 1000 ) ), MidpointRounding.AwayFromZero );
}
TimeSpan remaning = new TimeSpan( 0, 0, remainSec );
OnBinaryCopy( new BinaryCopyEventArgs( bytesReceived, percent, kbPSec, remaning ) );
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;
}
public double Percent { private set; get; }
public double KbPSec{ private set; get; }
public TimeSpan Remaning{ private set; get; }
public long BytesReceived { private set; get; }
}
|
Ich hoff' das geht so in Ordnung
|
|
22.09.2010 12:52
|
Beiträge des Benutzers |
zu Buddylist hinzufügen
|
|
Abt
myCSharp.de-Team
Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW
|
|
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 2 Monate. |
digicorder
myCSharp.de-Mitglied
Dabei seit: 10.06.2014
Beiträge: 1
|
|
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
|
|
|
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
Dabei seit: 20.07.2008
Beiträge: 14.488
Herkunft: BW
|
|
...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
|
|
|
|