Delphi-PRAXiS
Seite 4 von 6   « Erste     234 56      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile) (https://www.delphipraxis.net/187850-ini-inhalt-geht-sehr-seltenen-faellen-verloren-tmeminifile.html)

CodeX 10. Jan 2016 16:45

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1326565)
Bei UpdateFile wird immer eine neue Datei erzeugt und damit eine eventuell bestehende gelöscht.

Das Datei-Attribut "Erstellt" zeigt immer den Zeitpunkt des ersten Erstellens. Müsste sich dieser dann nicht jedes Mal ändern, wenn die Datei vollständig neu erzeugt wird?

Grundsätzlich gäbe es ja auch noch die Möglichkeit, komplett auf Datei-Operationen zu verzichten und in UpdateFile per 2xSaveToFile stets in zwei Dateien zu schreiben. Bricht der Schreibvorgang beim ersten Schreiben ab, ist die Original-Datei noch vorhanden. Bricht der Schreibvorgang beim zweiten Schreiben ab, ist die Backupdatei bereits erstellt worden.
Das würde den Aufwand quasi genau verdoppeln. Ob das jetzt viel mehr als die Löschen/Umbenennen/Erstellen-Varianten sind, mag ich nicht zu urteilen. Auf jeden Fall können sich dann keine Probleme durch Dateioperationen ergeben.

Uwe Raabe 10. Jan 2016 16:57

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von CodeX (Beitrag 1326574)
Das würde den Aufwand quasi genau verdoppeln. Ob das jetzt viel mehr als die Löschen/Umbenennen/Erstellen-Varianten sind, mag ich nicht zu urteilen.

Ich schon, aber das hängt natürlich stark davon ab, was du "viel mehr" nennst und wie groß die INI-Datei ist. Für den Benutzer wird das bei einer handlichen INI-Datei nicht bemerkbar sein. Bei einem Speedtest wirst du einen Faktor von knapp 2 messen können.

Zitat:

Zitat von CodeX (Beitrag 1326574)
Auf jeden Fall können sich dann keine Probleme durch Dateioperationen ergeben.

Na, dann...

nahpets 11. Jan 2016 12:59

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1326564)
Zitat:

Zitat von nahpets (Beitrag 1326563)
Die einfachste Methode für zwei Dateien wäre doch, die INI-Datei vor UpdateFile mit
Delphi-Quellcode:
if FileExists(ChangeFileExt(FFileName,'.Save')) then DeleteFile(ChangeFileExt(FFileName,'.Save'));
RenameFile(ChangeFileExt(FFileName,'.Save'), NewName);
umzubenennen und dann

Delphi-Quellcode:
UpdateFile;
auszuführen.

Beim Laden der INI-Datei wird geprüft, ob sie leer ist, wenn ja, wird geprüft, ob es die Umbenannte gibt, wenn ja, wird diese geladen.

Und worin unterscheidet sich das jetzt von meinem Vorschlag :gruebel:

Garnicht, hatte nur den Eindruck, dass Dein Vorschlag nicht so ganz vorstanden worden ist, und dahinter ein deutlich komplexerer Lösungsansatz vermutet wurde.

Uwe Raabe 11. Jan 2016 13:14

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von nahpets (Beitrag 1326638)
hatte nur den Eindruck, dass Dein Vorschlag nicht so ganz vorstanden worden ist, und dahinter ein deutlich komplexerer Lösungsansatz vermutet wurde.

Den Eindruck habe ich mittlerweile aber auch...

nahpets 11. Jan 2016 14:40

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Hab' mal so zum Spass 'nen INI-Historienkrimskram zusammengedaddelt:
Delphi-Quellcode:
const
  ciMaxKopieen       = 10; // Anzahl der maximal anzulegenden Sicherungskopieen.
  ciMindestIniGroesse = 21; // Die Ini-Datei muss eine Mindestgröße haben,
                            // unterhalb dieser Größe fehlen auf jeden Fall
                            // irgendwelche Einträge...
                            // Sei der Mindestinhalt der INI-Datei
                            // [Section]
                            // Ident=
                            // so muss ihre Größe mindestens 21 Byte sein.

function GetFileSize(const sFile: String): Int64;
var
  fFile : THandle;
  wfd  : TWIN32FINDDATA;
begin
  Result := 0;
  if not SysUtils.FileExists(sFile) then exit;
  fFile := Windows.FindFirstfile(pchar(sFile),wfd);
  if fFile = INVALID_HANDLE_VALUE then exit;
  Result := (wfd.nFileSizeHigh * (MAXDWORD)) + wfd.nFileSizeLow;
  Windows.FindClose(fFile);
  // Hier könnte man jetzt noch weitere Plausibilitätsprüfungen für
  // die INI-Datei machen...
end;

procedure Irgendwas;
var
          i        : Integer;
          ini      : TMemIniFile;
          sIniFile : String;
          sBakFileA : String;
          sBakFileB : String;
begin
  // Beim Programmstart:
  // Den Namen der INI-Datei festlegen.
  sIniFile := ChangeFileExt(Application.ExeName,'.ini');
  // Fehlt diese Datei oder ist ihre Größe kleiner der Mindestdateigröße?
  if not FileExists(sIniFile) or (GetFileSize(sIniFile) < ciMindestIniGroesse) then begin
    // Prüfen, ob wir eine der letzten 10 Sicherungskopien finden...
    for i := 1 to ciMaxKopieen do begin
      // Name der Sicherungskopie i erstellen.
      sBakFileA := Format('%s.%.3d',[sIniFile,i]);
      // Gibt es sie und ist sie größer/gleich der Mindestdateigröße?
      if FileExists(sBakFileA) and (GetFileSize(sBakFileA) >= ciMindestIniGroesse) then begin
        // Sicherungskopie umbennen auf den eigentlich gewünschten Dateinamen.
        RenameFile(sBakFileA,sIniFile);
        // Schleife verlassen.
        break;
      end;
    end;
  end;
  // Ini-Datei laden...
  ini := TMemIniFile.Create(sIniFile);

  // ... Weitere Programmlogik ...
  ini.WriteString('Section','Ident',sBakFileA);
  // ...

  // Beim Programmende:
  // (eventuell) vorhandene Sicherungskopieen löschen bzw. umbennen,
  // so dass wir immer eine Historie von maximal ciMaxKopieen Ini-Dateien haben.
  for i := ciMaxKopieen downto 2 do begin
    // Name der Sicherungskopie i und i - 1 erstellen.
    sBakFileA := Format('%s.%.3d',[sIniFile,i]);
    sBakFileB := Format('%s.%.3d',[sIniFile,i - 1]);
    // Sicherungskopie mit der höheren Nr. in der Endung löschen.
    DeleteFile(sBakFileA);
    // vorhergehende Sicherungskopie umbenennen.
    RenameFile(sBakFileB,sBakFileA);
  end;
  // Dateinamen für die erste Sicherungskopie erstellen
  sBakFileA := Format('%s.%.3d',[sIniFile,1]);
  // und die letzte INI-Datei in die erste Sicherungskopie umbenennen.
  RenameFile(sIniFile,sBakFileA);
  // Ini-Datei speichern.
  ini.UpdateFile;
  // und Schluss ist.
  ini.Free;
end;
Sinnvollerweise baut man sich 'nen Nachfolger von TMemIniFile und gibt diesem Nachfolger statt der Konstanten entsprechende Attribute.

Den "Kram" vom Programmstart übernehme man in das überschriebene Create, den "Kram" zum Programmende ins überschriebene Destroy oder zusammen mit UpdateFile in eine eigene Routine, die man auch separat zu wichtigen Zeitpunkten aufrufen kann und zusätzlich im Destroy aufruft.

CodeX 11. Jan 2016 20:31

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1326641)
Zitat:

Zitat von nahpets (Beitrag 1326638)
hatte nur den Eindruck, dass Dein Vorschlag nicht so ganz vorstanden worden ist, und dahinter ein deutlich komplexerer Lösungsansatz vermutet wurde.

Den Eindruck habe ich mittlerweile aber auch...

Hm, sind meine Bedenken wirklich so daneben? Immerhin versuche ich hier ein Problem zu lösen, das eigentlich gar nicht auftreten dürfte, es aber wohl aufgrund ganz blöder Umstände doch tun kann. Der Vorschlag mit dem Umbenennen beinhaltet aber ja wiederum einen für mich intransparenten Zustand: Was passiert während des Umbenennens? Wenn dieser Befehl intern aus mehreren Teilschritten besteht und der Prozess genau dazwischen Abbricht, kann die Datei dann ja auch wieder verloren gehen. Ich sage nicht dass das so ist, aber zumindest sehe ich hier eine (für mich) Unbekannte.

Sir Rufo 11. Jan 2016 20:42

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Eine Aktion kann eben erfolgreich oder nicht erfolgreich sein - liegt halt im Wesen einer Aktion.

Habe ich mehrere Aktionen, die voneinander abhängig sind und zudem noch wie hier sich gegenseitig beeinflussen, dann sollte man das mit einer Transaktion absichern.

NTFS unterstützt solche Transaktionen.

Innerhalb so einer Transaktion kannst du Dateien löschen, Dateien erzeugen, Dateien ändern und erst wenn du die Transaktion mit einem Commit abschließt, werden diese Änderungen festgeschrieben.

Tritt irgendein unvorhergesehenes Ereignis auf (Programm-Absturz, Rechner aus, ...) passiert einfach nichts.

Also genau das was du suchst :)

notAssertor 11. Jan 2016 20:54

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Wichtige Daten sollte man in Stein meißeln lassen. Sollte der Steinmetz beim Einhämmern versterben, hat man Pech gehabt!

Falls während einer zentral wichtigen Millisekunde der Rechner abschmiert, hat man halt die 100%ige Datensicherheit knapp verfehlt!

Wie wäre es denn mit einer Vollkaskoversicherungen gegen umweltbedingten Polleneinflug beim Einatmen, die Nasenreizung zuverlässig verhindert oder entschädigt?

OMG - SCNR :oops:

Uwe Raabe 11. Jan 2016 21:02

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von CodeX (Beitrag 1326675)
Was passiert während des Umbenennens? Wenn dieser Befehl intern aus mehreren Teilschritten besteht und der Prozess genau dazwischen Abbricht, kann die Datei dann ja auch wieder verloren gehen.

Ich kann es leider nicht direkt durch einen Artikel im MSDN belegen, aber ich hatte schon mehrfach erwähnt, daß das Umbenennen einer Datei innerhalb desselben Verzeichnisses lediglich den Verzeichniseintrag verändert. Der korrekte Ausdruck dafür ist MetaData Operation, welche unter NTFS als sicher gelten.

Zitat:

That said, note that NTFS does have recovery at the metadata level - in other words, updates concerning file system metadata are always atomic. The NTFS metadata will not become corrupted during a sudden reboot
siehe hier

Anhand der weiter oben beschriebenen Vorgehensweise existiert zum Zeitpunkt des Umbenennens die Sicherungsdatei nicht (wurde spätestens beim Create gelöscht). Wenn man aber sicher gehen will, kann man sie auch noch vor dem Umbennenen löschen. Das ist insofern unkritisch, weil die Original-INI ja noch existiert (soll ja gleich umbenannt werden). Wenn die Zieldatei nicht existiert, ist das simple Rename (wohlgemerkt unter NTFS und im selben Verzeichnis!) atomar.

Bei FAT-Systemen kann das allerdings schon wieder anders aussehen.

Uwe Raabe 11. Jan 2016 21:05

AW: Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1326676)
NTFS unterstützt solche Transaktionen.

Wäre da nicht dieser Hinweis (TxF = Transactional NTFS):
Zitat:

TxF may not be available in future versions of Microsoft Windows


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:44 Uhr.
Seite 4 von 6   « Erste     234 56      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz