AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Ini-Inhalt geht in sehr seltenen Fällen verloren (TMemIniFile)
Thema durchsuchen
Ansicht
Themen-Optionen

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

Ein Thema von CodeX · begonnen am 8. Jan 2016 · letzter Beitrag vom 12. Jan 2016
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.758 Beiträge
 
Delphi 12 Athens
 
#1

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

  Alt 10. Jan 2016, 15:08
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

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
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#2

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

  Alt 11. Jan 2016, 12:59
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

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
Garnicht, hatte nur den Eindruck, dass Dein Vorschlag nicht so ganz vorstanden worden ist, und dahinter ein deutlich komplexerer Lösungsansatz vermutet wurde.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.758 Beiträge
 
Delphi 12 Athens
 
#3

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

  Alt 11. Jan 2016, 13:14
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...
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#4

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

  Alt 11. Jan 2016, 14:40
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.
  Mit Zitat antworten Zitat
CodeX

Registriert seit: 30. Okt 2004
475 Beiträge
 
Delphi 12 Athens
 
#5

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

  Alt 11. Jan 2016, 20:31
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.
Nur Delphi schafft es, einem ein Lächeln zu schenken, wenn man sich beim Schreiben von := vertippt und stattdessen ein :) erscheint.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#6

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

  Alt 11. Jan 2016, 20:42
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
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
notAssertor
(Gast)

n/a Beiträge
 
#7

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

  Alt 11. Jan 2016, 20:54
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
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.758 Beiträge
 
Delphi 12 Athens
 
#8

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

  Alt 11. Jan 2016, 21:05
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
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.758 Beiträge
 
Delphi 12 Athens
 
#9

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

  Alt 11. Jan 2016, 21:02
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
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#10

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

  Alt 11. Jan 2016, 21:39
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.
Nein, Deine Bedenken sind selbstverständlich nicht daneben, aber die Sicherheit, die Du (vermutlich) anstrebst, wirst Du nicht erlangen.

Egal was Du in Deinem Programm machst:
Es ist immer möglich, dass zwischen zwei Programmschritten, die immer korrekt verlaufen, irgendwann doch mal der Strom weg ist, ein Hardwaredefekt auftritt, der Anwender einen Prozess abschießt...

Daher ja mein Vorschlag, immer wenn was wichtiges in der INI geändert wurde, UpdateFile aufzurufen.

Oder halt eine Routine implementieren, die Dir mehrere Sicherungeskopieen der Ini-Datei erstellen.

Dir scheint die Korrektheit und Speicherung der INI-Datei ja sehr wichtig zu sein. Beschreibe doch einfach mal kurz, warum, in welchem Umfeld...

Eventuell wird es für uns verständlicher, Deine Sorgen zu teilen und eventuell einen anderen Lösungsansatz zur Problemlösung zu finden.

Welche Datenmengen stehen in der INI-Datei?

Könnte eine Embedded-Firebird-Datenbank oder eine SQLite-Datenbank... oder sowas helfen?
Da sind die Daten in 'ner Transaktion per Commit weggeschrieben und der Stand ist dann beim nächsten Programmstart vorhanden, eine Datenbankdatei ist nicht bei 'nem misslungenen Update leer oder wird vor dem Schreiben gelöscht und dann neu erstellt.

Unter Delphi 7 sieht UpdateFile so aus:
Delphi-Quellcode:
procedure TMemIniFile.UpdateFile;
var
  List: TStringList;
begin
  List := TStringList.Create;
  try
    GetStrings(List);
    List.SaveToFile(FFileName);
  finally
    List.Free;
  end;
end;
In einer Ableitung könnte man das ja dahingehend überschreiben, dass man nach dem SaveToFile noch prüft, ob die Datei auch wirklich erstellt wurde und nicht leer ist.
Man könnte sie auch anschließend in eine zweite Stringliste laden und die beiden Stringlisten vergleichen...
Delphi-Quellcode:
procedure TMemIniFile.UpdateFile;
var
  List: TStringList;
  List2: TStringList;
begin
  List := TStringList.Create;
  List2 := TStringList.Create;
  try
    try
      // Hier eventuell die in früherem Post vorgeschlagene "Historisierung" älterer INI-Dateien einbauen...
      GetStrings(List);
      List.SaveToFile(FFileName);
      List2.LoadFromFile(FFileName);
      if List.Text <> List2.Text then begin
        MessageDLG('Abweichung zwischen vor und nach dem Speichern der INI-Datei.',mtError,[mbOk],0);
      end;
    except
      on e : Exception do begin
        // Irgendwelche Sicherungsmaßnahmen...
        MessageDLG(e.Message,mtError,[mbOk],0);
      end;
    end;
  finally
    List2.Free;
    List.Free;
  end;
end;
(Das ist jetzt nur mal so "hingedaddelt" und nicht getestet.)

Schau Dir bitte in den Delphi-Quellen mal GetStrings von TMemIniFile an, könnte da (bedingt durch die verwendeten Daten) eventuell ein Fehler auftreten?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:12 Uhr.
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