Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Daten schrittweise in Textdatei speichern (https://www.delphipraxis.net/159628-daten-schrittweise-textdatei-speichern.html)

Sim_Star 6. Apr 2011 07:56

Daten schrittweise in Textdatei speichern
 
Hallo,

ich frage mich gerade wie ich Daten schrittweise in eine Textdatei speichern kann.
Ich habe vor mir einen eigenen Logger zu programmieren, der mir in meinen Programmen Ereignisse und so weiter aufzeichnet und diese dann speichert.

Nun will ich gerne die Speicherung intern über eine Stringliste vornehmen. Da diese aber immer größer wird will ich diese nach Erreichen einer bestimmten Größe automatisch in eine Textdatei abspeichern, und die interen Liste leeren.

Wie kann man jetzt neue Daten wieder an die Textdatei, also ans Ende anhängen, ohne diese wieder z.b. zuerst in eine Stringliste zu laden?


Für Hilfe bin ich dankbar!

LG Marco

mleyen 6. Apr 2011 08:02

AW: Daten schrittweise in Textdatei speichern
 
Delphi-Referenz durchsuchenAssignFile
Delphi-Referenz durchsuchenAppend
Delphi-Referenz durchsuchenWriteln
Delphi-Referenz durchsuchenCloseFile

himitsu 6. Apr 2011 08:32

AW: Daten schrittweise in Textdatei speichern
 
- FileStream öffnen (wenn Datei nicht existiert, dann eine erstellen)
- Position ans Ende
- StringListe in diesen Stream kopieren (also anhängen)
- StringListe leeren

oder die besagten (alten) Textprozeduren (ala AssignFile und WriteLn)
oder Hier im Forum suchenFileStringList, bzw. Hier im Forum suchenPartialTextfile

rob74 6. Apr 2011 08:45

AW: Daten schrittweise in Textdatei speichern
 
Darf ich fragen, warum Du die Log-Messages in eine StringList speichern willst und erst in einem zweiten Schritt in eine Datei? Direkt in die Datei wäre deutlich einfacher (siehe: KISS-Prinzip), und hätte noch den Vorteil, dass die Daten in der Datei immer den aktuellen Zustand des Programms widerspiegeln, wenn das Programm z.B. abstürzt, kommst Du u.U. nicht mehr dazu, die Daten in die Datei zu speichern. Langsamer wird das Programm dadurch nicht, die Datei wird ja nicht bei jedem Aufruf direkt auf die Festplatte geschrieben, die diversen Caches auf Betriebssystems- und Festplattenebene federn das ab...

mleyen 6. Apr 2011 09:08

AW: Daten schrittweise in Textdatei speichern
 
@himi: ja stimmt, diese konvertiererei dieser Urzeitunits macht mich total Kirre... :wall:
Aber ich hab hier noch eine andere Variante, die dich bestimmt interessiert :stupid:

Delphi-Quellcode:
function SetFilePointer(hFile: Cardinal; lDistanceToMove: Longint; lpDistanceToMoveHigh: Pointer;
                        dwMoveMethod: Cardinal): Cardinal; stdcall; external kernel32 name 'SetFilePointer';

function FileExists(const FileName: string; const PFileSize: PInt64 = nil): Boolean; {$IFDEF Inln}inline;{$ENDIF}
var
  myFile: Cardinal;
  myFindData: TWin32FindData;
  TheInt64: Int64;
begin
  myFile := FindFirstFile(@FileName[1], myFindData);
  Result := myFile <> INVALID_HANDLE_VALUE;
  if Result then
  begin
    FindClose(myFile);
    if PFileSize <> nil then
    begin
      TheInt64 := PFileSize^;
      Int64Rec(TheInt64).Lo := myFindData.nFileSizeLow;
      Int64Rec(TheInt64).Hi := myFindData.nFileSizeHigh;
      PFileSize^ := TheInt64;
    end;
  end;
end;

function OpenFile(const FileName: string; var hFile: Cardinal; const PFileSize: PInt64 = nil): Boolean; {$IFDEF Inln}inline;{$ENDIF}
begin
  Result := FileExists(FileName, PFileSize);
  if Result then
  begin
    hFile := CreateFile(@FileName[1], GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, 0, 0);
    Result := hFile <> INVALID_HANDLE_VALUE;
  end;
end;

function WriteFileStr(const hFile: Cardinal; const AStr: string): Boolean; {$IFDEF Inln}inline;{$ENDIF}
var
  Size, BytesWritten: Cardinal;
begin
  Size := Length(AStr)*SizeOf(Char);
  Result :=
    (WriteFile(hFile, AStr[1], Size, BytesWritten, nil)) and
    (Size = BytesWritten);
end;

function AddTextToFile(const Text, FilePath: string): Boolean; {$IFDEF Inln}inline;{$ENDIF}
var
  hFile: Cardinal;
  fs: UInt64;
begin
  Result := false;
  if not OpenFile(FilePath, hFile, @fs) then
    Exit;
  if SetFilePointer(hFile, fs+Length(Text)*SizeOf(Char), nil, FILE_BEGIN) = fs+Length(Text)*SizeOf(Char) then
  begin
    SetEndOfFile(hFile);
    Result :=
      (SetFilePointer(hFile, fs, nil, FILE_BEGIN)=fs) and
      WriteFileStr(hFile, Text);
  end;
  CloseHandle(hFile);
end;

shmia 6. Apr 2011 10:35

AW: Daten schrittweise in Textdatei speichern
 
Zitat:

Zitat von mleyen (Beitrag 1093349)
Delphi-Quellcode:
function FileExists(const FileName: string; const PFileSize: PInt64 = nil): Boolean; {$IFDEF Inln}inline;{$ENDIF}

Diese Funktionen sind viel zu groß um um Inline kompiliert irgendeinen Sinn zu ergeben.
Ich kann nur empfehlen, diese Inline-Klauseln komplett wegzulassen!
Wenn man ausserdem noch bedenkt, dass der Zugriff auf Dateien Milliardenfach mehr Zeit benötigt als mit einer Inline-Funktion gespart werden könnte....

himitsu 6. Apr 2011 12:47

AW: Daten schrittweise in Textdatei speichern
 
Und solange die Log-Datei kleiner als 2 GB bleibt und man kein Unicode benötigt, funktionieren die alten Pascal-Datei-Funktionen auch noch ganz gut.

mleyen 6. Apr 2011 12:50

AW: Daten schrittweise in Textdatei speichern
 
@shmia:
Dafür gibts ja den Direktivenschalter.
Aber welchen Nachteil bekommt Entwickler und Anwender (außer der größeren Exe) doch gleich?

FBrust 6. Apr 2011 14:14

AW: Daten schrittweise in Textdatei speichern
 
Hallo,

ich verwende üblicherweise die folgende Procedure in einer separaten Unit:

Delphi-Quellcode:
procedure WriteLog(strText: string);
var tfLog: TextFile;
    strLogPath: string;
    strLogFile: string;
begin
      strLogPath := GetSpecialFolderLocation($23) + 'meinprogramm\Logs';
      if not DirectoryExists(strLogPath) then
        ForceDirectories(strLogPath);
      strLogFile := strLogPath + '\LOG-' + FormatDateTime('YYYY-MM-DD', Now()) + '.TXT';
      AssignFile(tfLog, strLogFile);
      if FileExists(strLogFile) then
        Reset(tfLog)
      else
        Rewrite(tfLog);
      Append(tfLog);
      WriteLn(tfLog, FormatDateTime('HH:MM:SS', Now()) + ' - ' + strText);
      CloseFile(tfLog);
end;
Dort, wo ich etwas protokollieren will, reicht dann ein einfaches

Delphi-Quellcode:
WriteLog('Das ist wichtig');
, um einen Protokolleintrag inklusive aktueller Zeit zu erstellen.

Man könnte das ganze noch in ein try..except oder try...finally packen, hat aber bisher ganz gut funktioniert.

Gruß
Frank

shmia 6. Apr 2011 15:35

AW: Daten schrittweise in Textdatei speichern
 
Zitat:

Zitat von mleyen (Beitrag 1093403)
Aber welchen Nachteil bekommt Entwickler ...

Die Inline-Klauseln sind ja völlig überflüssig, da sie bei den gezeigten Funktionen keinen Sinn machen.
Zusätzlich verwirren sie den Entwickler mit visuellem Störfeuer.
Je mehr Code ein Entwickler lesen muss, umso schlechter wird seine Leistung beim Verstehen von Sourcecode.

Siehe auch: Vorsicht vor Optimierungen

Maik81ftl 8. Apr 2011 22:03

AW: Daten schrittweise in Textdatei speichern
 
Zitat:

Zitat von Sim_Star (Beitrag 1093335)
Hallo,

ich frage mich gerade wie ich Daten schrittweise in eine Textdatei speichern kann.
Ich habe vor mir einen eigenen Logger zu programmieren, der mir in meinen Programmen Ereignisse und so weiter aufzeichnet und diese dann speichert.

Nun will ich gerne die Speicherung intern über eine Stringliste vornehmen. Da diese aber immer größer wird will ich diese nach Erreichen einer bestimmten Größe automatisch in eine Textdatei abspeichern, und die interen Liste leeren.

Wie kann man jetzt neue Daten wieder an die Textdatei, also ans Ende anhängen, ohne diese wieder z.b. zuerst in eine Stringliste zu laden?


Für Hilfe bin ich dankbar!

LG Marco

schaut nach 'ner Log-file aus :lol:

Zitat:

Zitat von mleyen (Beitrag 1093337)

sry a wan i sowas sehe, bekomm ich 'nen Anfall von :twisted:

Da ich selber auch sowas betreibe, würde ich auf diese version verweisen.

Delphi-Quellcode:
procedure Messwerterfassung(Messwert: String; Count: Longint);
var s: String;
begin
  fFilename:= Format('%s%s', [fPath, fExt]);
  if fFileName <> '' then
     begin
     with TIniFile.Create(fFileName) do try
       s := Format('[%s%s]', [fName, fLastname]);
       WriteString(s, 'Messwert' + IntToStr(Count), Messwert));
     finally
       Free;
     end;
  end;
end;
Würde dir anbieten eine klasse dafür zu coden.

Sir Rufo 8. Apr 2011 22:34

AW: Daten schrittweise in Textdatei speichern
 
Eine Ini-Datei als Log-Datei?

Der 1. April ist doch schon vorbei (hier wenigstens).

Bitte nicht - da kriegt man ja Schüttelfrost

Maik81ftl 8. Apr 2011 22:38

AW: Daten schrittweise in Textdatei speichern
 
Zitat:

Zitat von Sir Rufo (Beitrag 1094030)
Eine Ini-Datei als Log-Datei?

Der 1. April ist doch schon vorbei (hier wenigstens).

Bitte nicht - da kriegt man ja Schüttelfrost

war auch kein Aprilschwerz. oder steht irgenwo geschrieben, das dies unbedingt nur auf eine Ini angewendet werden darf??? ich selber habe dies nirgends gelesen. nur das man dies Beforzugt für ini anwendet.

und solange keine Textvormatierung gewünscht wird, schreib ich alles nach dem Schema.

man kann auch ein Memo extra einbinden und dies denne Speichern. kommt am ende auf das selbe Datenvollumen raus.

Aber ist ja am ende geschmackssache, wie es jeder macht. Dies bietet sich bei meinem projekten nun mal an, da ich mit StringGrid's arbeite. wenn ich ein Memo hätte,...

Ok da würd ich auch dies verwenden.

Sir Rufo 8. Apr 2011 22:51

AW: Daten schrittweise in Textdatei speichern
 
Wenn man ein Log schreiben möchte, dann ist es äußerst kontraproduktiv eine Variante zu wählen, wo die bisherigen Einträge zunächst geladen werden müssen und dann zum Abschluss alles wieder gespeichert.

Bei kleinen MiniLogs mag das evtl. noch vertretbar sein, aber ... wozu gibt es die Möglichkeit direkt an eine Datei etwas dranzuhängen.

Stream auf, Daten dranhängen, Stream zu.
Schneller und einfacher geht es nicht.

himitsu 9. Apr 2011 06:51

AW: Daten schrittweise in Textdatei speichern
 
TIniFile ... bist du krank?

Die dahinterlegende WinAPI ließt die komplette Datei in den Arbeitsspeicher, ändert dann etwas, bzw. fügt die neue Zeile ein, und schreibt dann alles komplett neu auf die Festplatte.
(PS: Darum gibt es in vielen Windows-Systemen für INIs eine Größenbegrenzung von 64 KB, da ein fester 64 KB Puffer für diese Änderungen genutzt wird)

Maik81ftl 9. Apr 2011 08:07

AW: Daten schrittweise in Textdatei speichern
 
Zitat:

Zitat von himitsu (Beitrag 1094037)
TIniFile ... bist du krank?

Nö nur des Wahnsinst fette Beute :lol:

Zitat:

Zitat von himitsu (Beitrag 1094037)
Die dahinterlegende WinAPI ließt die komplette Datei in den Arbeitsspeicher, ändert dann etwas, bzw. fügt die neue Zeile ein, und schreibt dann alles komplett neu auf die Festplatte.
(PS: Darum gibt es in vielen Windows-Systemen für INIs eine Größenbegrenzung von 64 KB, da ein fester 64 KB Puffer für diese Änderungen genutzt wird)

sry, Aber ich hab mit den 64KB kein Streß, liegt wohl auch daran, das ich Unter Ubuntu meine Proggis schreibe.


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:44 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