2016-07-21 12 views
1

Ich benutze QFile als Datei-Reader und einen Datei-Writer, um Dateien aus meiner Anwendung auf USB zu kopieren. Ich habe versucht herauszufinden, warum meine Dateikopien auf USB (mit Fortschrittsbalken) so lange dauern. Ich habe schließlich herausgefunden, dass wenn ich das QFile-Objekt schließe, das zum Schreiben verwendet wird, kann die close() - Operation viel länger als die tatsächliche Schreiboperation dauern. Dies sind sehr große Dateien, und ich lese/schreibe Blöcke von 16384 Bytes, und dann sende ich ein Signal an die GUI, um den Fortschrittsbalken zu erhöhen, der vom Benutzer betrachtet wird. Ich habe nach jedem Schreibvorgang einen Aufruf von flush() hinzugefügt, da ich annehme, dass dies der Fall ist, weil der Ausgangsstrom noch nicht auf die Festplatte geschrieben wurde. Das machte keinen Unterschied. Das Schließen des ausgehenden QFile-Objekts dauert immer noch viel länger als die Schreibzeit (Timing vor und nach dem Kopieren und vor und nach jedem der QFile :: close() - Aufrufe wurde der Timing-Code entfernt) Leichtigkeit des Lesens, ich debuggte auch und sah es passiert). Natürlich hilft es nicht, die close() -Funktion aufzurufen, da die Zerstörung des QFile-Objekts dazu führt, dass es aufgerufen wird.Qt5 QFile :: close() sehr langsam zum Schreiben

Mein Code ist wie folgt (minus Fehlerkontrolle, Zielraum Prüfung, etc.):

void FileCopy::run() 
{ 
    QByteArray bytes; 
    int totalBytesWritten = 0; 
    int inListSize = inList.size(); 

    for (int i=0; !canceled && i<inListSize; i++) 
    { 
     QString inPath = inList.at(i).inPath; 
     QString outPath = inList.at(i).outPath; 
     QFile inFile(inPath); 
     QFile outFile(outPath); 
     int filesize = inFile.size(); 
     int bytesWritten = 0; 

     if (!inFile.open(QIODevice::ReadOnly)) 
     { 
      return; 
     } 

     if (!outFile.open(QIODevice::WriteOnly)) 
     { 
      inFile.close(); 
      return; 
     } 

     // copy the FCS file with progress 
     while (!canceled && bytesWritten < filesize) 
     { 
      bytes = inFile.read(MAXBYTES); 
      qint64 outsize = outFile.write(bytes); 
      outFile.flush(); 
      if (outsize != bytes.size()) 
      { 
       break; 
      } 
      bytesWritten += outsize; 
      totalBytesWritten += outsize; 
      Q_EMIT signalBytesCopied(totalBytesWritten, i+1, inListSize); 
      QThread::usleep(100); // allow time for detecting a cancel 
     } 

     inFile.close(); 
     outFile.close(); 
    } 

    // Other error checking done here 
} 

Kann jemand einen Weg finden, um diese übergeben zu bekommen? Ich würde eigentlich bevorzugen, dass der Fortschrittsbalken sich langsamer bewegt und den Zustand der Kopie für den Benutzer genauer anzeigt, als dass der Fortschrittsbalken in weniger als der Hälfte der Zeit, die für die Kopie benötigt wird, 100% und zum Abschluss tatsächlich vollständig ist.

Ich habe auch versucht, mit QSaveFile anstelle von QFile für die Ausgabe, aber QSaveFile :: commit() hat das gleiche genaue Problem, mehr Zeit zum Festschreiben als die eigentliche Kopierschleife zu beenden. Ich nehme an, dass dies daran liegt, dass darunter die gleiche Funktionalität wie QFile verwendet wird, die von QIoDevice abgeleitet ist.

Ich habe überlegt, auf die Verwendung von Standard-Streams umzusteigen, möchte aber etwas Konsistenz bei der Handhabung der Datei in dieser Anwendung beibehalten. Es ist jedoch eine Möglichkeit, wenn QFile :: close() so lange zum Schließen braucht. Oder ist es möglich, dass der Standardstream das gleiche Problem hat?

Ich arbeite an einer Win7 32-Bit-Box mit VS2010 mit Qt5.1.1 und dem Qt 1.2.2 VS-Add-In. Danke für Anregungen.

Antwort

1

Während Sie schreiben, speichert das Betriebssystem wahrscheinlich nur die Schreibvorgänge im Speicher (schnell). Aber wenn Sie die Datei schließen, muss sie alle Daten auf Festplatte (langsam - vor allem, wenn es noch nicht geschrieben hat). Das Schließen der Datei muss also darauf warten, dass das Betriebssystem alle Daten auf die Festplatte (USB) legt und dass tatsächlich alles zu dieser Zeit sein kann.

Der Grund, warum Betriebssysteme so etwas tun, ist natürlich, Schreibvorgänge zu beschleunigen - und oft können sie dann die Daten im Hintergrund auf die Festplatte spülen, wenn nichts anderes passiert (also nicht wirklich Beachten Sie die tatsächlichen Kosten, da sie sich im Laufe der Zeit amortisieren, wenn nichts anderes passiert. Aber wenn Sie nur schreiben und dann sofort schließen, werden Sie es bemerken. Hinweis: Die Alternative wäre, dass die Schreibanrufe langsamer sind - Sie würden immer noch die gleiche tatsächliche Zeit ausgeben.

+0

Wie ich vermutete. Aus der Sicht des Benutzers würde ich es lieber sehen, wenn der Fortschrittsbalken 100% erreicht und dann die Kopie gemacht wird, anstatt 100% zu erreichen und immer noch die gleiche Zeit oder länger warten zu müssen Kopie zu tun. Meine Frage an diesem Punkt wäre, warum flush() nicht blockiert, bis es tatsächlich die Daten auf die Festplatte geleert hat, bevor es zurückkehrt? Wenn ich es dazu bringen könnte, würde der Fortschrittsbalken den Zustand der Kopie für den Benutzer genauer darstellen. In diesem Zusammenhang interessiere ich mich eher für die Genauigkeit des Berichtskopierstatus. – bmahf

+0

Also gibt es keine Möglichkeit, den Schreibvorgang zum Zeitpunkt des Aufrufs von flush() auf die Festplatte zu bringen? Die Schnittstelle zum Benutzer wird dadurch erschwert, dass sie keine Ahnung haben, warum die Fortschrittsanzeige länger als 100% sitzt. – bmahf

+0

Sie könnten versuchen, mit 'sync',' fsync' und ähnlichem zu spielen. Ich bin kein Windows-Experte, also weiß ich nicht, was ich dort tun soll. –