Laden...

Kopiergeschwindigkeit berechnen...

Erstellt von lord_fritte vor 9 Jahren Letzter Beitrag vor 9 Jahren 5.820 Views
L
lord_fritte Themenstarter:in
553 Beiträge seit 2007
vor 9 Jahren
Kopiergeschwindigkeit berechnen...

Hallo ich bastel gerade an einer Funktion um eine Datei zu kopieren.
Bis jetzt funktioniert das ganz gut. ABER: hat jemand eine Idee wie ich berechnen kann wie viel Bytes/Sekunde kopiert werden?


FileInfo sourceFile = new FileInfo(sourcePath);
FileInfo destinationFile = new FileInfo(destinationPath);
FileStream sourceStream = sourceFile.OpenRead();
FileStream destinationStream = destinationFile.OpenWrite();
int fileBufferSize = 8192;
int copiedBytes = 0;
Byte[] copyBuffer = new Byte[fileBufferSize];

while ((copiedBytes += sourceStream.Read(copyBuffer, 0, fileBufferSize)) > 0)
{
  destinationStream.Write(copyBuffer, 0, fileBufferSize);
  Console.WriteLine("{0} bytes von {1} bytes kopiert, {2} bytes/Sekunde", copiedBytes, sourceFile.Length, 0);
}

2.078 Beiträge seit 2012
vor 9 Jahren

Dazu müsstest du wissen, wie schnell wie Festplatten(n) sind, die dabei aktiv werden müssen.
Und noch mehr: Du musst alle relevanten Daten der Festplatte auslesen und darüber hinaus auch noch wissen, wie sehr die Festplatte von anderen Festplatten ausgelastet wird.

Das alles heraus zu finden sprengt den Rahmen ziemlich sicher.

Wenn das viele kleine Dateien sind, dann kannst du ja eine Progress-Bar anzeigen, die mit jeder Datei einen Schritt weiter geht.
Bei einer großen Datei kannst du grob schätzen, aber wirklich genau wird das nicht. Eine Möglichkeit wäre ja, bei einer einzelnen Datei heraus zu finden, wie lange 100 Byte brauchen. Dazu müsstest du aber viele Tests brauchen, denn zwischen verschiedenen Dateien hast du auch Zugriffszeiten, die gut ins Gewicht fallen.

Windows hat ja lange auch eine fleißig hopsende Progress-Bar beim Kopieren angezeigt, erst ab Windows 7 habe ich das nicht mehr so extrem bemerkt.

PS: Warum kopierst du die Datei selber?
Nutze doch einfach File.Copy

L
lord_fritte Themenstarter:in
553 Beiträge seit 2007
vor 9 Jahren

Weil "File.Copy" so statisch ist, da kommt im Grunde nichts zurück. Ich möchte schon gerne in regelmäßigen Abständen ein Feedback bekommen, dass der Vorgang noch läuft und wie viel schon abgeschlossen ist.

5.657 Beiträge seit 2006
vor 9 Jahren

Hi lord_fritte,

abgesehen von den Einwänden von Palladin007 handelt es sich bei der Berechnung um einen einfachen Dreisatz: Die Anzahl der bisher kopierten Bytes verhält sich zur bisher verstrichenen Zeit, wie die Gesamt-Byte-Anzahl zur Gesamt-Zeit.

Die Zeit messen kannst du mit der Stopwatch-Klasse.

Christian

Weeks of programming can save you hours of planning

3.825 Beiträge seit 2006
vor 9 Jahren

Obwohl die Berechnung so einfach ist hat es Microsoft im Datei-Explorer erst nach 20 Jahren hinbekommen, in Windows 8.

Grüße Bernd

Workshop : Datenbanken mit ADO.NET
Xamarin Mobile App : Finderwille Einsatz App
Unternehmenssoftware : Quasar-3

1.346 Beiträge seit 2008
vor 9 Jahren

Du könntest auch das Kopieren der Dateien, und das anzeigen des Fortschrittdialoges mit Restdaueranzeige komplett Windows überlasen mittels SHFileOperation. Das Windows API Code Pack hat das soweit ich weiss alles vorgefertigt drin.

LG

L
lord_fritte Themenstarter:in
553 Beiträge seit 2007
vor 9 Jahren

Ich habe das ganze mal ein bisschen erweitert:


static void Copy(string sourcePath, string destinationPath)
    {
      FileInfo sourceFile = new FileInfo(sourcePath);
      FileInfo destinationFile = new FileInfo(destinationPath);
      FileStream sourceStream = sourceFile.OpenRead();
      FileStream destinationStream = destinationFile.OpenWrite();
      int fileBufferSize = 8192;
      int copiedBytes = 0;
      int readBytes = 0;
      Byte[] copyBuffer = new Byte[fileBufferSize];

      long bytesPerSecond = 0L;
      int lastTicks = Environment.TickCount;
      long lastBytes = 0L;

      for (int i = 0; (readBytes = sourceStream.Read(copyBuffer, 0, fileBufferSize)) > 0; i++)
      {
        destinationStream.Write(copyBuffer, 0, fileBufferSize);
        copiedBytes += readBytes;

        if ((Environment.TickCount - lastTicks) >= 1000)
        {
          bytesPerSecond = copiedBytes - lastBytes;
          lastBytes = copiedBytes;
          lastTicks = Environment.TickCount;
        }

        Console.WriteLine("{0} bytes von {1} bytes kopiert, {2} bytes / Sekunde", copiedBytes, sourceFile.Length, bytesPerSecond);
      }
    }

Aber ich weiß jetzt nicht ob die Berechnung nicht stimmt, oder ob es wirklich dauernd zwischen 9 mb/s und 120 mb/s schwankt.

49.485 Beiträge seit 2005
vor 9 Jahren

Hallo Palladin007,

hat jemand eine Idee wie ich berechnen kann wie viel Bytes/Sekunde kopiert werden?

Dazu müsstest du wissen, wie schnell wie Festplatten(n) sind, die dabei aktiv werden müssen.
Und noch mehr: Du musst alle relevanten Daten der Festplatte auslesen und darüber hinaus auch noch wissen, wie sehr die Festplatte von anderen Festplatten ausgelastet wird.

Äh, nein! Wenn wirklich gefragt ist, was in der Frage steht, muss man lediglich die Anzahl der (in der letzten Sekunde) kopierten Bytes durch die verstrichene Zeit (also durch bei einer Sekunde durch eins teilen). Wenn man das Kopieren in kleine Häppchen zerlegt, die (weit) weniger als eine Sekunde dauern, ist es kein Problem, diese Informationen aus dem gezeigten Code in Kombination mit DateTime.Now oder Stopwatch zu ermitteln.

Und selbst wenn man die voraussichtliche Gesamtzeit bzw. voraussichtliche Restzeit ermitteln will, reichen die von mir genannten Informationen/Informationsquellen zusammen mit der Gesamtzahl an zu kopierenden Bytes. Das geht dann so, wie es MrSparkle gesagt hat. Es ist also wesentlich einfacher, als du es darstellst.

EDIT: In Grunde so, wie es lord_fritte jetzt auch gemacht hat. Sein Beitrag hat sich mit meinem überschnitten.

Hallo zusammen,

das Problem mit dem FileCopyDialog liegt wohl im wesentlichen an zwei Ursachen:

Zum einen am Abschätzen (bzw. Verschätzen) der Restmenge an zu kopierenden Bytes, gerade wenn eine Verzeichnisstruktur rekursiv kopiert wird und dadurch zu Anfang nicht bekannt ist, welche Datenmenge sich noch in tieferliegenden Verzeichnissen befindet.

Zum anderen die - zumindest auf mechanischen Festplatten - sehr unterschiedliche Kopiergeschwindigkeit, je nachdem, ob die zu kopierenden Bytes sich in wenigen großen oder vielen kleinen Dateien befinden.

Vor allem die Kombination beider Punkte, dass man also nicht weiß, was einen in tieferliegenden Verzeichnissen an Datenmenge und Verteilung auf Dateigrößen erwartet, und dass dies in den verschiedenen Unterverzeichnissen sehr unterschiedlich sein kann, führt dann zu den großen Schwankungen der Restzeitanzeige.

Hallo lord_fritte,

so starke Schwankungen sollten zumindest nicht regelmäßig/systematisch auftreten, will meinen, die die Anzeige sollte nicht ständig abwechselnd zwischen 9 und 120 hin und her springen. Anderseits sind gewisse Schwankungen normal, insbesondere wenn im Wechsel ein paar große und dann wieder viele kleine Dateien kopiert werden oder parallel von anderen Anwendungen weitere Plattenzugriffe erfolgen.

Um solche Schwankungen zu vermeiden, kann man die Zeitdauer verlängern (z.B. auf fünf Sekunden) bzw. den Durchschnitt der jeweils letzten (z.B. fünf) Messwerte anzeigen.

herbivore

L
lord_fritte Themenstarter:in
553 Beiträge seit 2007
vor 9 Jahren

@herbivore Danke!

Also was ich vergessen habe zu erwähnen. Ich kopiere in meinem Test nur eine Datei, die ist 3,53 GB groß.
Ich teste mal die bytesPerSecond zusammen zu zählen und durch i zu teilen.

EDIT: Ach ne quatsch! ich brauche eine neue Zählvariable, welche ebenfalls nur im Sekundentakt hochgezählt wird.

16.807 Beiträge seit 2008
vor 9 Jahren

Du kannst Dir QuickIO.NET - Performante Dateioperationen anschauen.
Das Kopieren läuft hier mit Chunks; und eine Zeitberechnung ist ebenfalls integriert bzw. dadurch erst möglich.