Seite 1 von 1

Frage zu QFile

Verfasst: 29. Dezember 2009 10:36
von TK
Hallo zusammen,

ich habe folgende zwei Funktionen:

Code: Alles auswählen

bool Parser::openOutputFile(const QString &OutputFilePath)
{
    bool Status = true;
    OutputFile = new QFile(OutputFilePath);

    Status = OutputFile->open(QIODevice::WriteOnly);
    if (false == Status)
    {
        QMessageBox::warning(this,
                             SSPGeneratorVersion,
                             tr("Kann Datei nicht speichern %1:\n%2.")
                             .arg(OutputFilePath)
                             .arg(OutputFile->errorString()));
    }

    return Status;
}

void Parser::closeOutputFile(const QString &OutputFilePath)
{
    bool Status = true;

    if (true == OutputFile->remove())
    {
        OutputFile->close();
        if (true == OutputFile->exists(OutputFile->fileName()))
        {
            Status = false;
        }
    }
    else
    {
        Status = false;
    }

    if (false == Status)
    {
        QMessageBox::warning(this,
                             SSPGeneratorVersion,
                             tr("Kann Datei nicht schließen %1:\n%2.")
                             .arg(OutputFilePath)
                             .arg(OutputFile->errorString()));
    }
}
Ich starte die Anwendung, es wird ein OutputFile mit openOutputFile erzeugt und geöffnet, was hineingeschrieben, auf dem Desktop gespeichert (mein ausgewählter Speicherort, z.B. test.txt) und mit closeOutputFile wieder geschlossen.

Nun lösche ich die auf dem Desktop gespeicherte Datei test.txt und möchte wieder etwas abspeichern. Aber es erscheint keine neue abgespeicherte Datei auf dem Desktop. Die Anwendung läuft ohne Fehler.

Wenn ich jedoch closeOutputFile auskommentiere, kann ich beliebig abspeichern (test.txt wird erzeugt und geschrieben).

Also ist der Wurm in closeOutputFile, aber warum?

Danke für Tipps und Hinweise :)

Verfasst: 29. Dezember 2009 10:54
von franzf
closeOutputFile schließt dein File intelligenterweise nicht nur, es entfernt es!
Ein QFile::remove() schließt die Datei eh vorher, das close in closeOutputFile() ist demnach unnötig.

Warum willst du denn unbedingt über mehrere Funktionsaufrufe hinweg ein QFile als Member erhalten? (BTW: du löschst es nie... Wenn das öfters passiert hast du ein nettes MemoryLeak ;))

Wie läuft denn die Routine des File-Beschreibnes genau? erledigt das eine Funktion auf einen Schwupps, oder läuft dein Programm einige Zeit, und das File ist eine Art Log?
Erzähl mal genauer!

Verfasst: 29. Dezember 2009 11:33
von TK
Hey franzf,

also, wenn ich dich richtig verstehe:

QFile::remove() schließt die Datei UND löscht sie anschließend vom Speicherort (sprich test.txt verschwindet vom Desktop).

Das ist ja kappes!

Also sieht die close-Fkt nun so aus:

Code: Alles auswählen

void Parser::closeOutputFile()
{
    OutputFile->close();
    delete OutputFile;            // <-- destructor  
    OutputFile = (QFile *) 0;  // <-- destructor
}
Habe es schon getestet, geht. Durch

Code: Alles auswählen

    delete OutputFile;          
    OutputFile = (QFile *) 0;
kommt auch kein MemoryLeak zustande, korrekt? Die beiden Zeilen kommen noch in den Destructor der Klasse Parser.

Die Klasse Parser schreibt unterschiedliche Informationen in eine Datei und um eine bessere Struktur zu erhalten gibt es mehrere Funktionen der Klasse Parser die diese Informationen schreiben, u.a. werden auch Infomationen aus anderen Dateien benötigt, um diesen Output zu generieren.
Die Routine des File-Beschreibens erledigt das zwar in einem Schwupps, aber dann wäre der Code nicht mehr lesbar.

Verfasst: 29. Dezember 2009 11:54
von franzf
bool QFile::remove ()
Removes the file specified by fileName(). Returns true if successful; otherwise returns false.

The file is closed before it is removed.
Ich finde es nicht sehr schön, wenn eine Datei über so lange Zeit geöffnet bleibt. Wenn dein Programm crasht, ist die Datei vllt. am Ende kaputt...

Ich würde die generierte Info in einem QByteArray puffern. Wenn das fertig ist einfach in der einen Methode den QByteArray in die Datei schreiben und fertig.

Alternativ kannst du doch in den Funktionen zum Schreiben nicht einen QString übergeben, sondern ein QFile*. Dann legst du lokal die Datei am Anfang der Schreibe-Funktion an und gibst das immer an die einzelnen Funktionen weiter.
Kannst du auch mit dem QByteArray machen!
Würde aber die Methode über das QByteArray bevorzugen.

Code: Alles auswählen

void generateInfoA( QByteArray& a );
void generateInfoB( QByteArray& a );
void generateInfoC( QByteArray& a );

void writeGeneratedInfo(const QString& fn)
{
  QByteArray buffer;

  generateInfoA(buffer);
  generateInfoB(buffer);
  generateInfoC(buffer);

  QFile file(fn);
  file.open(QIODevice::WriteOnly);
  file.write(buffer);
  file.close();
}

Verfasst: 29. Dezember 2009 12:41
von TK
Vielen Dank, dass du mir deinen 1000ten Beitrag gewidmet hast :wink:

Über QByteArray ist auch ein Ansatz. Das wäre dann in meinem Fall ein Puffer mit der Größe von ca. 700000 Zeichen! Ist das nicht ein bisschen groß?

Verfasst: 29. Dezember 2009 12:59
von franzf
TK hat geschrieben:Vielen Dank, dass du mir deinen 1000ten Beitrag gewidmet hast :wink:
Bitte bitte :P
Über QByteArray ist auch ein Ansatz. Das wäre dann in meinem Fall ein Puffer mit der Größe von ca. 700000 Zeichen! Ist das nicht ein bisschen groß?
Ich denke 700000 ist jetzt nicht wirklich schlimm.
Der Gedanke war einfach nur, auf Membervariablen für ein nicht dauerhaft notwendiges (also eigentlich temporäres) Objekt zu verzichten.

Versuch es mit einem QByteArray. Wenn du nicht ausreichend Speicher haben solltest (was ich bezweifle), dann wähle einen anderen Weg, z.B.:

Code: Alles auswählen

void generateInfoA( QDataStream& s );
void generateInfoB( QDataStream& s );
void generateInfoC( QDataStream& s );

void writeGeneratedInfo(const QString& fn)
{
  QFile file(fn);
  file.open(QIODevice::WriteOnly);

  QDataStream str(&file);

  generateInfoA(str);
  generateInfoB(str);
  generateInfoC(str);

  file.close();
}
Wenn es nur Plaintext ist, kannst du auch einfach einen QTextStream nehmen.
Du kannst - wenn es deine Struktur erlaubt - auch die einzelnen Info-Generatoren in Klassen packen und für diese den operator<< implementieren. Das wäre die in meinen Augen schönste Lösung, aber für kleinere Probleme wohl zu viel "Overhead".