Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Neuen Beitrag zur Code-Library hinzufügen (https://www.delphipraxis.net/33-neuen-beitrag-zur-code-library-hinzufuegen/)
-   -   Delphi TStrings.SaveToFileSafety (https://www.delphipraxis.net/152583-tstrings-savetofilesafety.html)

himitsu 28. Jun 2010 11:45


TStrings.SaveToFileSafety
 
Wenn man über SaveToFile z.B. etwas speichert und beim Speichern etwas passiert (z.B. irgendeine Exception), dann sind alle Daten futsch.

Sowohl die Originaldatei, wenn vorher noch eine alte gleichnamige Datei existierte, sowohl eventuell auch die aktuellen Daten.

Diese Funktion legt daher eine temporäre Datei an, speichert darin die Stringliste und tauscht im Nachhinein, wenn alles Erfolgreich war, die Dateien erst aus.

Als Bonus bleibt die Originaldatei sogar noch erhalten.
Ein "normales" SaveToFile überschreibt ja die alten Daten unwiederruflich.
Dabei bleibt das alte Original entweder im Papierkorb erhalten oder es ließe sich eine Weile lang über entsprechende Datenrettungstools aus dem Dateisystem wiederherstellen.
(gelöschte Dateien werden ja nicht sofort im Dateisystem entfernt/überschrieben)

Delphi-Quellcode:
Uses RTLConsts, ShellAPI;

Type TStringsSafetyHelper = Class Helper for TStrings
    Procedure SaveToFileSafety(Const FileName: String;
      BackupToRecycler: Boolean = False); Overload;
    Procedure SaveToFileSafety(Const FileName: String; Encoding: TEncoding = nil;
      BackupToRecycler: Boolean = False); Overload;
  End;

Procedure TStringsSafetyHelper.SaveToFileSafety(Const FileName: String;
    BackupToRecycler: Boolean = False);

  Begin
    SaveToFileSafety(FileName, nil, BackupToRecycler);
  End;

Procedure TStringsSafetyHelper.SaveToFileSafety(Const FileName: String; Encoding: TEncoding = nil;
    BackupToRecycler: Boolean = False);

  Var H, Hs: THandle;
    i:      Integer;
    Stream: TStream;
    SHFile: TSHFileOpStruct;

  Begin
    Hs := CreateFile(PChar(FileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
    If Hs <> INVALID_HANDLE_VALUE Then Begin
      H := INVALID_HANDLE_VALUE;
      Try
        i := -1;
        Try
          Repeat
            Inc(i);
            H := CreateFile(PChar(Format('%s.%d', [FileName, i])), GENERIC_READ or GENERIC_WRITE,
              0, nil, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, Hs);
          Until (H <> INVALID_HANDLE_VALUE) or (i >= $FFFF);
          If H = INVALID_HANDLE_VALUE Then
            Raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
          Stream := THandleStream.Create(H);
          Try
            SaveToStream(Stream, Encoding);
          Finally
            Stream.Free;
          End;
          FlushFileBuffers(H);
          If BackupToRecycler Then Begin
            SHFile.Wnd   := 0;
            SHFile.wFunc := FO_DELETE;
            SHFile.pFrom := PChar(FileName + #0);
            SHFile.pTo   := nil;
            SHFile.fFlags := FOF_ALLOWUNDO or FOF_NOCONFIRMATION or FOF_NOERRORUI or FOF_NO_UI or FOF_SILENT;
            If not SHFileOperation(SHFile) Then
              Raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
          End Else If not Windows.DeleteFile(PChar(FileName)) Then
            Raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
          If not MoveFile(PChar(Format('%s.%d', [FileName, i])), PChar(FileName)) Then Begin
            i := -1;
            Raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
          End;
        Except
          If i <> -1 Then Windows.DeleteFile(PChar(Format('%s.%d', [FileName, i])));
          Raise;
        End;
      Finally
        CloseHandle(H);
      End;
    End Else SaveToFile(FileName, Encoding);
  End;
So wie die Funktion ist, läßt sie sich nur ab Delphi 2009 nutzen,
aber indem man einfach nur den Encoding-Parameter entfernt, würde es bis runter zu Delphi 2006 / Turbo Delphi funktionieren.
Und für noch ältere Delphi-Versionen muß man sich "nur" eine eigene Klasse/Funktion aus diesem Class-Helper basteln. :angel:

Die ganze Speicherroutine liese sich auch auf andere Dateispeicherungen anwenden, nicht nur für Stringlisten.
Dafür müßte man dann halt nur die Speicherroutinen des Objektes anpassen/austauschen und z.B. einen passenden Class-Helper erstellen.

mkinzler 28. Jun 2010 11:47

AW: TStrings.SaveToFileSecure
 
Wobei die Bezeichnung ...Secure etwas ungünstig ist, da man eher erwartet, das verschlüsselt o.ä. wird

himitsu 28. Jun 2010 11:51

AW: TStrings.SaveToFileSecure
 
Bin für Vorschläge offen ... mir war einfach nix besseres eingefallen. :stupid:

blackfin 28. Jun 2010 11:53

AW: TStrings.SaveToFileSecure
 
Mhm...vielleicht mit einem Wortspiel? :)

TStrings.SafeToFile() :D

oder...WriteSafeToFile() ;

mkinzler 28. Jun 2010 11:54

AW: TStrings.SaveToFileSecure
 
Vielleicht .SaveToFileBackuped() oder noch besser wäre eine überladenen Variante mit ensprechenden Parameter

mirage228 28. Jun 2010 11:54

AW: TStrings.SaveToFileSecure
 
Wie wärs mit SafeSaveToFile()? ;-)

Im Englischen gibt es ja den Unterschied zwischen Safety und Security...

blackfin 28. Jun 2010 11:58

AW: TStrings.SaveToFileSecure
 
Und noch ein paar Vorschläge:

SaveToFileProved()

SaveToFileReliable() ;

SaveCertainlyToFile()

himitsu 28. Jun 2010 12:04

AW: TStrings.SaveToFileSafety
 
Besser so?


Die Wortspiele, wie SafeToFile, würde ich nicht gern nutzen.
- Erstmal sieht es so zu ähnlich aus (Verwechslungsgefahr)
- und dann macht es sich mit einem Suffix besser, bezüglich der Autovervollständigung.

mirage228 28. Jun 2010 12:07

AW: TStrings.SaveToFileSafety
 
Fast. Klingt nun etwas komisch (also der Englische Ausdruck). "SaveToFileSafely" (oder auch "SaveToFileSafe") wäre da korrekter.

blackfin 28. Jun 2010 12:08

AW: TStrings.SaveToFileSafety
 
SaveToFileWithHaarSpaltereiWort()


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:48 Uhr.
Seite 1 von 2  1 2      

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