![]() |
ForceFile
Es gibt ja ein ForceDirectory, aber kein ForceFile.
Deshalb habe ich eines gemacht. Ist zwar nicht spektakulär, aber für faule Menschen wie mich ;-) ForceFile erstellt eine Textdatei, wenn sie noch nicht vorhanden ist. Optional: Löscht und erstellt eine Textdatei, wenn sie schon vorhanden ist (z.B., wenn man den Inhalt einer vorhandenen Textdatei löschen möchte und mit einer leeren Textdatei beginnen möchte).
Delphi-Quellcode:
procedure ForceFile(dateiname: string; bereits_vorhandene_datei_trotzdem_neu_erstellen: boolean = False);
var f: text; begin { bereits_vorhandene_datei_trotzdem_neu_erstellen -> True. z.B. wenn man eine leere Datei haben will, und ein bereits vorhandener Dateiinhalt nicht mehr weiterverwendet werden soll } if not FileExists(dateiname) then begin assignfile(f, dateiname); rewrite(f); //writeln(f, ''); closefile(f); end; if bereits_vorhandene_datei_trotzdem_neu_erstellen then begin DeleteFile(dateiname); assignfile(f, dateiname); rewrite(f); //writeln(f, ''); closefile(f); end; end; Beispiel:
Delphi-Quellcode:
ForceFile('bericht.txt');
Oder auch eine vorhandene Datei neuerstellen:
Delphi-Quellcode:
ForceFile('bericht.txt',True);
Man spart sich im eigentlichen Code ein paar Zeilen Code. |
AW: ForceFile
Delphi-Quellcode:
Eine weitere Möglichkeit.
function MakeFile(const AFilename: string; const AOverwrite: Boolean = False; const AShowError: Boolean = False): Boolean;
const INVALID_HANDLE_VALUE = THandle(-1); var h: THandle; begin Result := False; if (AFilename = '') then Exit; if (AOverwrite and FileExists(AFilename)) then if (not DeleteFile(AFilename)) then begin if AShowError then ShowMessage('File deletion for "' + AFilename + '" failed.'); Exit; end; if (not FileExists(AFilename)) then begin h := FileCreate(AFilename); if (h = INVALID_HANDLE_VALUE) then begin if AShowError then ShowMessage('File creation for "' + AFilename + '" failed.'); Exit; end else begin FileClose(h); Result := True; end; end else Result := True; end; //Edit, methode ist nun eine function und man könnte es als "if makefile('blabla.bla')" nutzen |
AW: ForceFile
Delphi-Quellcode:
:stupid:
procedure ForceFile(dateiname: string; bereits_vorhandene_datei_trotzdem_neu_erstellen: Boolean = False);
var f: Text; begin if not FileExists(dateiname) or bereits_vorhandene_datei_trotzdem_neu_erstellen then begin //DeleteFile(dateiname); // nicht nötig, weil der Inhalt wird ja eh gelöscht/überschrieben AssignFile(f, dateiname); Rewrite(f); //WriteLn(f, ''); CloseFile(f); end; end; Das behebt auch das "Problemchem" mit dem doppelten Erstellen, wenn NotExist und bereits_vorhandene... Alernativ wäre ein ELSE zwischen den IF auch eine Lösung dafür. |
AW: ForceFile
Mir erschließt sich noch nicht ganz der Sinn der ganzen Aktion. Für einen Lesezugriff ist das ja eher uninteressant, eine leere Datei zu erstellen bzw. eine existierende mit einer leeren ersetzen. Für das Lesen ist doch eher wichtig ob die Datei überhaupt existiert.
Beim Schreiben hilft mir das aber auch nicht viel weiter, da kann ich dann nach dem ForceFile zwar auf das Create verzichten und ein simples OpenFile verwenden, aber der Aufwand in ForceFile erscheint mir dafür nicht wirklich angemessen. In solchen Fällen verwende ich dann eher einen ![]() Ich bin aber offen für Szenarien, bei denen eine solche Funktionalität sinnvoll sein kann. |
AW: ForceFile
@Uwe
Ich habe es verwendet für TSTringList.loadFromFile() . Da muss es die Datei schon geben. Und ich wollte nur ein einfaches Protokoll/Bericht anfertigen, das dann auch evtl. weitergeführt werden sollte. Da finde ich den Einzeiler dann schon ganz nett, und muss nicht denn Programmablauf, mit file exists und so weiter "stören": forcefile(datei) Stringlist.create StringList.loadfromFile(datei) ... |
AW: ForceFile
Da du sowieso ein FileExists benutzt, warum dann nicht einfach
Delphi-Quellcode:
?
if FileExists(...) then SL.LoadFromFile(..);
|
AW: ForceFile
Das würd' ich dann aber noch etwas anpassen:
Delphi-Quellcode:
Bei fehlender Verzeichnisstruktur wird Deine Variante (vermutlich) scheitern, himitsus Einzeiler
function ForceFile(dateiname: string; bereits_vorhandene_datei_trotzdem_neu_erstellen: Boolean = False) : Boolean;
var f: Text; begin Result := ForceDirectories(ExtractFilePath(Dateiname)); if Result then begin if not FileExists(dateiname) or bereits_vorhandene_datei_trotzdem_neu_erstellen then begin AssignFile(f, dateiname); ReWrite(f); CloseFile(f); end; end; Result := FileExists(dateiname); end; ... if ForceFile(datei) then begin Stringlist.Create; StringList.LoadfromFile(datei); ... StringList.SaveToFile(datei); StringList.Free; end else begin // Fehlerbehandlung ... end;
Delphi-Quellcode:
ebenfalls, wenn die Stringliste per SaveToFile gespeichert werden soll.
if FileExists(...) then SL.LoadFromFile(..);
|
AW: ForceFile
Das ForceDirectory reicht beim Speichern.
Beim Laden ist es egal. Die Datei ist so oder so nicht da (oder leer), egal ob man das Verzeichnis und/oder die Datei noch erstellt. Und eine dann neue leere Datei zu laden macht auch keinen Sinn. (*1) *1) Einzig um beim Laden bereits zu prüfen, ob die Datei später auch gespeichert werden kann, aber auch a kann man direkt mir einem Read/Write-Schreibzugriff die Datei öffnen (ohne ihren Inhalt zu löschen) und direkt laden. |
AW: ForceFile
Zitat:
Bei 'ner Logdatei ist's halt "blöde", wenn nach stundenlangem Programmlauf festgestellt wird, dass die Logdatei nicht geschrieben werden kann. Ist halt ärgerlich, kommt aber zuweilen schonmal im realen Leben vor. Daher mach' ich lieber ein paar Prüfungen zuviel, als irgendwann auf die Nase zu fallen. Wenn das ForceDirectories bereits am Anfang scheitert, weiß man, dass man nicht sinnvoll weitermachen kann, auch wenn das ForceDirectories letztlich unmittelbar vor dem SaveToFile ausreichen würde. Natürlich ist es nicht sinnvoll eine leere Datei zuladen, Nichts in 'ner Stringliste ist halt eben Nichts in 'ner Stringliste, aber ich weiß dann schonmal sicher, dass ich Nichts habe und muss nicht mehr damit rechnen, dass ich im weiteren Programmverlauf nichtmal Nichts haben werde ;-) Beim ForceFile weiß ich aber, dass das Verzeichis erstellt werden kann und das in dem Verzeichnis eine Datei erstellt werden kann. Man könnte die Funktion noch um eine IO-Prüfung erweiteren, so dass damit dann auch noch eventuell vorhandene Rechteprobleme, ... festgestellt werden könnten und dort einem nicht unerwarten eine Exception um die Ohren fliegt.
Delphi-Quellcode:
Und ja, die Frage ist, wieviel Aufwand will man da treiben?
function ForceFile(dateiname: string; bereits_vorhandene_datei_trotzdem_neu_erstellen: Boolean = False) : Integer;
var f : Text; bOk : Boolean; iIOResult : Integer; begin Result := 0; bOk := ForceDirectories(ExtractFilePath(Dateiname)); if bOk then begin if not FileExists(dateiname) or bereits_vorhandene_datei_trotzdem_neu_erstellen then begin AssignFile(f, dateiname); {$I-} ReWrite(f); {$I+} Result := IOResult; CloseFile(f); end; end else begin Result := -MaxInt; end; end; ... iIOResult := ForceFile(datei); case iIOResult of 0 : begin Stringlist.Create; StringList.LoadfromFile(datei); ... StringList.SaveToFile(datei); StringList.Free; end; // hier ggfls. andere Werte von iIOResult gezielt abfragen und entsprechend reagieren. else // Fehlerbehandlung ... end; end; |
AW: ForceFile
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). ![]()
Delphi-Quellcode:
Alternativ alles zufammenfassen und daraus nur eine "Prüfung" bauen.
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;
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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:14 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 by Thomas Breitkreuz