Seite 1 von 1

QSettings Problem mit Laden und Speichern in Dateien

Verfasst: 28. März 2011 09:53
von a.m.blub
Hiho,
ich hab ein kleines Problem und komm nicht mehr weiter.
Ich wollte mit Hilfe von QSettings einstellungen meiner Anwendung in einer Inidatei abspeichern und laden. Inclusive einer Prüfung ob sich die zu speichernden Daten seit dem letzten Abspeichern geändert haben.

Mein Problem ist nun wenn die ini Datei zum Beispiel schreibgeschützt ist.
Mein Vergleich zwischen den gespeicherten und den aktiven daten beim ersten durchlauf korrekt ist aber beim 2 durchlauf nicht mehr korrekt ist.

Testdatei (schreibgeschützt)
test.ini:
[General]
testvalue=test

fehlerhafte Funktion:

Code: Alles auswählen

void Main::testsetting()
{
    mysetting=new QSettings("test.ini",QSettings::IniFormat);
    if(mysetting->value("testvalue").toString()==testvalue) //wird beim 2. Aufruf durchlaufen
        {
            QMessageBox::information(this,"Check","Testvalue="+testvalue+ " ist gleich dem gespeicherten wert="+mysetting->value("testvalue").toString(),QMessageBox::Ok);
        }
        else //wird beim 1. Aufruf korrekt durchlaufen
        { 
            QMessageBox::information(this,"Check","Testvalue="+testvalue+ " ist ungleich dem gespeicherten wert="+mysetting->value("testvalue").toString(),QMessageBox::Ok);
        }
        mysetting->setValue("testvalue",testvalue);
        mysetting->sync();
        if(mysetting->status() ==QSettings::NoError)   QMessageBox::information(this,"Save","Speichern erfolgreich",QMessageBox::Ok);
        else QMessageBox::information(this,"Save","Speichern nicht erfolgreich",QMessageBox::Ok);
    delete mysetting;


}
Was ich nicht verstehe ist obwohl ich das Qsettingsobjekt zerstöre.
Und beim 2. Aufruf neu erzeuge und da die Datei schreibgeschützt ist unverändert neu lade.
Scheint er intern irgendwie auf den im ersten Versuch erzeugten Filesstream zuzugreifen in den die Änderungen gespeichert aber nicht auf das Orginalfile zurückgeschrieben wurde zuzugreifen.

Was bedeuten würde das wenn ich ein neues Qsetting Objekt erstelle mit Zugriff auf ein File das vorher versucht wurde zu Speichern, ich in dem neuen QSetting Objekt einen inkonsistenten Datensatz lade. :(

Effekt tritt unter Linuxumgebung wie auch unter Windows auf.
Benutze Version QT4.7
Komplettes Beispiel im Anhang.

Verfasst: 28. März 2011 19:45
von ScyllaIllciz
Das wird Dir zwar nicht wirklich weiter helfen aber warum erstellst Du das Objekt auf dem Heap und nicht auf dem Stack, wenn Du es nur diesem Scope brauchst? Was ist wenn zwischendurch eine Ausnahme geworfen wird, dann hast Du ein unnötiges Speicherleck!

Verfasst: 28. März 2011 20:05
von franzf
AFAIK cached QSettings die Einstellungen. Hat den Hintergrund, dass du nicht selber ständig QSettings-Objekte speichern oder bei verteilter Nutzung der Settings rumreichen oder referenzieren musst. Einfach Objekt erstellen, wird geparst, und liegt dann im Speicher, auch wenn das Objekt zerstört wurde. An anderer Stelle öffnest du ein Settings-Objekt, das die selbe Datei verwendet, und du hast ohne Zeitverlust direkt die Einstellungen.

Ich hab aber keinen Link zu einem Beweis (und grad keine Zeit in die SOurcen zu schauen:P), das klebt nur noch irgendwo in meinem Hirn.

Verfasst: 29. März 2011 07:31
von a.m.blub
Ob Heap oder Stack macht keinen Unterschied das Problem bleibt.

Ich hab kein Problem damit das er die Datei selbst nach der Zerstörung im Cache hält. Mein Problem ist das er einen inkonsitenten Zustand im Cache hält und beim erneuten Zugriff (Laden des Files) den inkonsistenten Zustand benutzt anstatt in dem Fall was logisch wäre. Die gecachte Version zu aktualisieren.

Daher die Frage kann man entweder irgendwie den Cache leeren oder eine Aktualisierung der gecachten Daten erreichen.

Würde nämlich ungern wegen der 15 Werte die ich Speichern will eine Serialiesierungsfunktion basteln zumal QSettings ja eigentlich dafür gedacht ist Programmeinstellungen zu speichern.

Verfasst: 29. März 2011 08:42
von franzf
Ich weiß nicht, was du unter inkonsistenter Zustand verstehst. Sei mal genauer.
Hier ist beim ersten Speichern "test" in den settings, beim zweiten dann der Wert von "testvalue". testvalue ist bei dir ein leerer String. Wenn du den mit was Ordentlichem füllst, ist es vllt. nicht so verwirrend.

Verfasst: 29. März 2011 10:04
von a.m.blub
Ob der String in testvalue leer ist oder einen anderen Wert hat wie z.b. "andererWert" der Effekt ist der gleiche.

Mit inkonsistent Zustand meine ich das die Daten von der Datei die sich im Cache befinden nicht mit den Daten aus der Datei übereinstimmen.

Sprich beim ersten "Speichern" wird die Datei in den Cache geladen.
testvalue hat hier den Wert "test" im Cache sowie auch in der Datei auf der Platte. Beim Vergleich wird dann auch Korrekt festgestellt das Wert von "testvalue=test" mit dem leeren String oder wenn man den String mit einen anderen Wert füllt nicht übereinstimmt.

Anschließend wird versucht den neuen Wert in die Schreibgeschützte Datei zu schreiben. Sprich so wie das im Moment sehe wird der neue Wert für "testvalue" in den cache geschrieben. Und anschließend versucht die Daten im cache in die Datei zu schreiben was fehlschlägt.

Daten im Cache und Daten in der Datei sind jetzt nicht mehr gleich (inkonsistenter Zustand).

Problem jetzt beim 2. Ausführen von "Speichern" werden einfach die Daten aus dem Cache verwendet die nicht mit den Daten der Datei übereinstimmen. Was dazu führt das beim Gleichheitstest fälschlicher Weise behauptet wird das "testvalue" im Programm mit dem Wert in meiner Datei übereinstimmt, was nicht der Fall ist.

Wenn ich mein QSetting Objekt nicht zerstören würde wäre das Verhalten ja nachvollziehbar.
Aber wenn ich das Objekt zerstöre und anschließend ein neues Lade mit der gleichen Datei dann gehe ich davon aus das die Datei neu geladen wird oder zumindest vom Cachemanagment geprüft wird ob die Daten im Cache mit denen in der Datei übereinstimmen und gegebenfalls aktualisiert werden.

Verfasst: 30. März 2011 16:31
von franzf
Dann passt doch alles. Ich bin mir sicher, dass sich die Qtler bei dem Verhalten was gedacht haben. Z.B. dass Änderungen an den Settings unabhängig von der dauerhaften Existenz eines Objektes über die gesamte Laufzeit des Programms erhalten bleiben sollen. Wäre doch Käse, wenn nur MainWindow ein QSettings-Objekt speichert, eine andere Klasse aber schon vorher schreibend drauf zugreift, das QSettings-Objekt nicht speichert, und das MainWindow dann mit FALSCHEN Settings startet.

QSettings ist sowieso recht langsam, da du den Umweg über QVariant + cast gehen musst.
Für dein Vorhaben würde ich ein anderes Vorgehen empfehlen. Schreib dir ein "struct Settings;", in dem alle Einstellungsknöpfchen mit ihrem konkreten Typ gespeichert werden.. Schreib dir auch eine Funktion "Settings getDefaultSettings();" o.Ä., die die Einstellungen aus der ini lesen, in ein Settings-Objekt packen und zurückgeben. Das Objekt kannst du jetzt beliebig verändern, trotzdem bekommst du immer noch ein Default-Objekt, wenn du willst.