Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi ForceFile (https://www.delphipraxis.net/211068-forcefile.html)

Uwe Raabe 24. Jul 2022 13:46

AW: ForceFile
 
Zitat:

Zitat von himitsu (Beitrag 1509152)
Man kann sich ja einfach mal den Code des LoadFromFile vornehmen und dort den Dateizugriff anpassen.

Etwa so?
Delphi-Quellcode:
type
  TStringsHelper = class helper for TStrings
    procedure LoadFromFile(const FileName: string); overload;
    procedure LoadFromFile(const FileName: string; Encoding: TEncoding); overload;
  end;

procedure TStringsHelper.LoadFromFile(const FileName: string; Encoding: TEncoding);
begin
  if FileExists(FileName) then
    inherited;
end;

procedure TStringsHelper.LoadFromFile(const FileName: string);
begin
  if FileExists(FileName) then
    inherited;
end;

himitsu 24. Jul 2022 14:36

AW: ForceFile
 
Ja, für das reine Abfangen der Exception, wenn die Datei noch nicht existiert.

Mach noch ein SaveToFile ans Ende deiner Methoden, dann hast auch gleich sofort den Schreibzugriff mit geprüft.

Und/oder ins SaveToFile zumindestens noch ein ForceDirectory.

KodeZwerg 24. Jul 2022 14:46

AW: ForceFile
 
Zitat:

Zitat von himitsu (Beitrag 1509152)
Man kann sich ja einfach mal den Code des LoadFromFile vornehmen und dort den Dateizugriff anpassen.
In diesem Fall also OPEN_EXISTING durch OPEN_ALWAYS ersetzen und zusätzlich auch den Schreibzugriff zu aktivieren (siehe SaveToFile).
https://docs.microsoft.com/en-us/win...#CREATE_ALWAYS

Delphi-Quellcode:
uses System.RTLConsts;

procedure TForm9.FormCreate(Sender: TObject);
var
  FN: string;
  SL: TStringList;
  FS: {TFileStream}THandleStream;
  FH: THandle;
begin
  FN := ChangeFileExt(Application.ExeName, '.txt');
  SL := TStringList.Create;
  try
    ForceDirectories(ExtractFileDir(FN));
    FH := CreateFile(PChar(FN), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil,
      {OPEN_EXISTING}OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
    if FH = INVALID_HANDLE_VALUE then
      //RaiseLastOSError;
      raise EFCreateError.CreateFmt(SFCreateErrorEx, [ExpandFileName(FN), SysErrorMessage(GetLastError)]);
    try
      FS := THandleStream.Create(FH); // hatte der HandleStream nicht mal ein "Owns" und konnte das Handle dann selber freigeben? 
      try
        SL.LoadFromStream(FS);
      finally
        FS.Free;
      end;
    finally
      CloseHandle(FH);
    end;

    //...

    SL.SaveToFile(FN);
  finally
    SL.Free;
  end;
end;
Alternativ alles zufammenfassen und daraus nur eine "Prüfung" bauen.

Delphi-Quellcode:
procedure TForm9.FormCreate(Sender: TObject);
var
  FN: string;
  SL: TStringList;
  FH: THandle;
begin
  FN := ChangeFileExt(Application.ExeName, '.txt');
  SL := TStringList.Create;
  try
    ForceDirectories(ExtractFileDir(FN));
    FH := CreateFile(PChar(FN), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil,
      {OPEN_EXISTING}OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
    if FH = INVALID_HANDLE_VALUE then
      //RaiseLastOSError;
      raise EFCreateError.CreateFmt(SFCreateErrorEx, [ExpandFileName(FN), SysErrorMessage(GetLastError)]);
    CloseHandle(FH);

    SL.LoadFromFile(FN);

    //...

    SL.SaveToFile(FN);
  finally
    SL.Free;
  end;
end;


Der FileHandle (FH) und FileStream (FS) ließen sich auch bis zum Ende behalten und direkt zum Schreiben benutzen.
Da kann zwischendrin auch nicht die Datei, bzw. das Schreibrecht und das Sharingrecht verschwieden, weil es die ganze Zeit bestehen bleibt.

Delphi-Quellcode:
procedure TForm9.FormCreate(Sender: TObject);
var
  FN: string;
  SL: TStringList;
  FS: {TFileStream}THandleStream;
  FH: THandle;
begin
  FN := ChangeFileExt(Application.ExeName, '.txt');
  SL := TStringList.Create;
  try
    ForceDirectories(ExtractFileDir(FN));
    FH := CreateFile(PChar(FN), GENERIC_READ or GENERIC_WRITE, FILE_SHARE_READ, nil,
      {OPEN_EXISTING}OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
    if FH = INVALID_HANDLE_VALUE then
      //RaiseLastOSError;
      raise EFCreateError.CreateFmt(SFCreateErrorEx, [ExpandFileName(FN), SysErrorMessage(GetLastError)]);
    try
      FS := THandleStream.Create(FH);
      try
        SL.LoadFromStream(FS);

        //...

        FS.Position := 0;
        FS.Size := 0; // oder nach dem Speichern ein Truncate
        SL.SaveToStream(FS);
        //FS.Truncate; // gibt es nicht, aber Size zuweisen geht ja auch, sowie auch über das Handle
        // also FS.Size := FS.Position;
        // oder SetEndOfFile(FH);
      finally
        FS.Free;
      end;
    finally
      CloseHandle(FH);
    end;
  finally
    SL.Free;
  end;
end;

Du hast seinen Wunsch einer "leeren" Datei vergessen glaube ich. Also eine existierende Datei "leeren".

himitsu 24. Jul 2022 14:50

AW: ForceFile
 
Nein. :angle:

Die Hilfe lesen?
MSDN-Library durchsuchenOPEN_ALWAYS



@Uwe: Schöner wäre es, wenn Die Load/Save ohne Encoding auf die Version mit Encoding gehen würden, anstatt den Stream jeder selber zu erstellen.
So hätte man statt Helper die Klasse unterm selben Namen ableiten und nur zwei Funktion (die mit Encoding) überschreiben müssen.

Am Ende landet ja eh alles bei LoadFromStream/SaveToStream mit Encoding.

Uwe Raabe 24. Jul 2022 16:37

AW: ForceFile
 
Zitat:

Zitat von himitsu (Beitrag 1509159)
@Uwe: Schöner wäre es, wenn Die Load/Save ohne Encoding auf die Version mit Encoding gehen würden, anstatt den Stream jeder selber zu erstellen.
So hätte man statt Helper die Klasse unterm selben Namen ableiten und nur zwei Funktion (die mit Encoding) überschreiben müssen.

:) https://quality.embarcadero.com/browse/RSP-38725

Rollo62 25. Jul 2022 08:12

AW: ForceFile
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1509138)
Mir erschließt sich noch nicht ganz der Sinn ...

Ja, das ist auch mein HauptProblem damit.

Ich könnte mir zwar vorstellen das es da sinnvoll sein könnte wo zwingend Files vorhanden sein sollten, z.B. .ini, .log,
um die Abläufe zu vereinheitlichen bei einfachen Files an denen angehängt werden soll.

Wenn bei Programmstart einmal ForceFile aufgerufen wird, werden diese auf jeden Fall angelegt und nutzbar und man muss sich beim Schreiben nicht mehr drum kümmern.

Trotzdem würde ich auf ein FileExists niemals verzichten und die Frage wäre dann was passieren soll wenn das File doch fehlt (hat irgendwer wie Virenscanner gelöscht).
Dann müsste man das File ja doch wieder an der Stelle neu createn, was ein ForceFile bei Programmstart wieder überflüssig machen würde.

Ein Beispiel wo man ForceFile unbedingt braucht wäre schön :stupid:

KodeZwerg 25. Jul 2022 08:59

AW: ForceFile
 
er spart sich halt beim programm start eine seperate abfrage (könnte theoretisch sofort auf irgend eine art "laden") aber prüft leider kein ergebnis, himitsu sein vorschlag mit einem permanent geöffneten handle plus prüfung finde ich pers. am sinnvollsten für seinen zweck.
(wenn sinn und zweck sein soll sicherzustellen das solange das programm aktiv ist auch diese datei für das programm zur verfügung steht)

Uwe Raabe 25. Jul 2022 10:41

AW: ForceFile
 
Zitat:

Zitat von KodeZwerg (Beitrag 1509185)
er spart sich halt beim programm start eine seperate abfrage

Nicht wirklich. Die Abfrage wird lediglich in ForceFile verlagert - mit einer signifikanten Menge anderem Code. Statt eine FileExists-Abfrage muss nun ein ForceFile gemacht werden, wobei das auch nur für den Moment gilt und beim LoadFromFile schon wieder obsolet sein kann.

Wie schon anderweitig gesagt:
Zitat:

Zitat von Rollo62 (Beitrag 1509181)
Ein Beispiel wo man ForceFile unbedingt braucht wäre schön

Betonung auf unbedingt braucht.

Union 25. Jul 2022 11:03

AW: ForceFile
 
@Monday: Wozu der Weg über eine TStringList? Führst Du Sortierungen durch oder willst die neuesten Sätze zuerst in der Datei haben? Falls nicht, setze doch
Delphi-Quellcode:
TFile.AppendAllText
ein. Die Prozedur besitzt auch einen optionalen Encoding Parameter.

himitsu 25. Jul 2022 11:19

AW: ForceFile
 
Zitat:

Zitat von Union (Beitrag 1509201)
Falls nicht, setze doch
Delphi-Quellcode:
TFile.AppendAllText
ein. Die Prozedur besitzt auch einen optionalen Encoding Parameter.

weil
Zitat:

FreePascal / Lazarus


Aber Notfalls gäbe es auch noch die alten File-API
Delphi-Referenz durchsuchenAppend
oder Delphi-Referenz durchsuchenTStringStream und selber zum Dateiende springen


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:13 Uhr.
Seite 2 von 3     12 3      

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 by Thomas Breitkreuz