Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Tail Funktionalität (https://www.delphipraxis.net/140625-tail-funktionalitaet.html)

gsh 22. Sep 2009 13:22


Tail Funktionalität
 
Hallo Leute,

Es kennen doch von euch sicher viele die Programme "Tail for Win32", "WinTail" oder unter Linux "tail". Genau diese Funktionalität will ich in meinem Programm auch implementieren.

Falls jemand die Programme nicht kennt: Diese Programme öffnen eine Datei und zeigen automatisch neue Zeilen an die nach dem Öffnen in die Datei geschrieben wurde. Am besten vorstellbar bei Log Dateien: Wenn eine neue Zeile vom Programm geloggt wird dann kann man diese sofort sehen und muss nicht die Log-Datei neu öffnen.

Meine Frage ist jetzt wie ich so etwas am besten realiesieren könnte. Jedesmal mit LoadFromFile die Datei neu laden und dann auf Änderungen überprüfen ist glaub ich keine gute Lösung.

mleyen 22. Sep 2009 13:28

Re: Tail Funktionalität
 
Du könntest in regelmäßigen Abständen die Werte der Dateigröße und 'Zuletzt geändert am' auf Änderung prüfen.
Erst wenn sich diese Werte verändert haben wird die Datei neu geladen und auf den Inhalt geprüft.

Es gab aber auch mal eine Komponente namens "FileWatcher", ich glaub hier aus der DP. Evtl. könnte man da mal nachschauen, wie die die Änderungen feststellt.

Klaus01 22. Sep 2009 13:32

Re: Tail Funktionalität
 
.. hier ein ähnlicher Ansatz:

Zitat:

AndersonCarli:
You may save last file size and then read from that pos.
Try this: (not compiled)
Delphi-Quellcode:
function Tail(FileName:string; Position:Integer):string;
var
  S: TStream;
  C: Char;
  L: Integer;
begin
  S := TFileStream.Create(FileName, fmOpenRead ,fmShareDenyNone);
  try
    S.Seek(Position, soBeginning);
    L := S.Size-Position;
    SetLength(Result, L);
    S.Read(Result[1], L);
  finally
    S.Free;
  end;
end;

Quelle

Grüße
Klaus

mkinzler 22. Sep 2009 13:32

Re: Tail Funktionalität
 
Sollte mt Hilfe eines FileStreams funktionieren.

Btw. Tail zeigt den Schluss ( letzte n-Zeilen an)

Assertor 22. Sep 2009 13:34

Re: Tail Funktionalität
 
Hi,

Stichwort: FindFirstChangeNotification, z.B. implementiert in ATFileNotification (Komponente).

Gruß Assertor

gsh 22. Sep 2009 13:50

Re: Tail Funktionalität
 
Also ich fass es mal kurz zusammen:
* Sagen wir mal jede Sekunde die Dateigröße überprüfen.
* Wenn die Dateigröße kleiner geworden ist (sollte eigentlich nicht vorkommen) -> Datei komplett neu einlesen
* Wenn die Dateigröße größer geworden ist dann über den Filestream die letzten Änderungen einlesen (Post #3)

Dies klingt für mich mal ganz gut (Hätte ich eigentlich auch selbst drauf kommen können :oops: ). Die Methode sollte dann sogar über ftp funktionieren :mrgreen: .

Zitat:

Zitat von Assertor
Stichwort: FindFirstChangeNotification, z.B. implementiert in ATFileNotification (Komponente).

Ist wahrscheinlich die Ressourcen schonenste Variante aber es geht wahrscheinlich nicht über eine Windows Freigabe (und ganz sicher nicht über ftp) oder? (Hab vergessen zu schreiben das das auch wichtig ist.)

gsh 22. Sep 2009 14:01

Re: Tail Funktionalität
 
So hab das jetzt kurz probiert und bin gleich mal auf ein Problem gestoßen:
Im Projekt Project1.exe ist eine Exception der Klasse EFOpenError mit der Meldung 'Datei C:\Testlogdatei.log kann nicht geöffnet werden. Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird' aufgetreten.

Die Log-Datei wird vom Server exklusiv exklusiv geöffnet (kann ich nicht ändern). Deswegen kann mein Programm darauf nicht zugreifen. Der Witz ist aber das z.b. WinTail es schafft die Datei trotzdem auszulesen. Wie macht WinTail das?

himitsu 22. Sep 2009 14:46

Re: Tail Funktionalität
 
Es gibt hier schon ein paar Threads zu diesem Thema "Auf Dateien zugreifen, welche geöffnet sind"
z.B. http://www.delphipraxis.net/internal...t.php?t=141044

In irgendeinem hatte ich mal eine Demo gepostet, welche sobald sie erstmal Zugriff auf die Datei (vie Filehandle und mit den geltenden Zugriffs- und Sharingrechten erhalten hat, diesen immer behält und danach andere Programm normal drauf zugreifen können, da dann an den Sharingrechten vorbeigelesen wird :stupid:
(ich finde nur den schon ein paar Jahre alten Thread nimmer, aber da ging's darum zu erkennen ob eine Datei vor irgendeinem Programm geöffnet ist),
aber wenn ich mich nicht irre, dann würde dieser Weg dir wohl nicht viel helfen, da (glaube ich zumindestens grade) die nur der Bereich zugreifbar ist, welcher schon existierte und nichts aus Dateivergrößerungen ... müßte ich irgendwann mal schauen, ob ich das so richtig in erinnerung hab.

PS: Die Zugriffsprobleme, welche du beim Lesen hast, hat das andere Programm auch,
also wenn du grad dabei bist die Datei auszulesen und das andere Programm da grad was reinschreiben will ... *peng* und, wenn du Pech hast, das andere Programm macht sonstwas :stupid:

Morphie 22. Sep 2009 16:33

Re: Tail Funktionalität
 
Du könntest einfach die Datei temporär kopieren, dann sollte das doch eigentlich klappen, oder?
müsstest du beim FTP ja sowieso, oder?

gsh 22. Sep 2009 17:16

Re: Tail Funktionalität
 
Zitat:

Zitat von himitsu
Es gibt hier schon ein paar Threads zu diesem Thema "Auf Dateien zugreifen, welche geöffnet sind"
z.B. http://www.delphipraxis.net/internal...t.php?t=141044

Bringt mir nichts da es ganz wichtig ist das z.b. so eine datei: \\entfernterpc\freigabe\datei.log auch geöffnet werden kann. Da der Service der auf die Datei zugreift somit nicht auf dem gleichen System ist ...

Zitat:

Zitat von himitsu
In irgendeinem hatte ich mal eine Demo gepostet, welche sobald sie erstmal Zugriff auf die Datei (vie Filehandle und mit den geltenden Zugriffs- und Sharingrechten erhalten hat, diesen immer behält und danach andere Programm normal drauf zugreifen können, da dann an den Sharingrechten vorbeigelesen wird :stupid:
(ich finde nur den schon ein paar Jahre alten Thread nimmer, aber da ging's darum zu erkennen ob eine Datei vor irgendeinem Programm geöffnet ist),
aber wenn ich mich nicht irre, dann würde dieser Weg dir wohl nicht viel helfen, da (glaube ich zumindestens grade) die nur der Bereich zugreifbar ist, welcher schon existierte und nichts aus Dateivergrößerungen ... müßte ich irgendwann mal schauen, ob ich das so richtig in erinnerung hab.

Der Service greift immer als erstes und andauerend auf die Datei zu. Somit geht diese Lösung leider auch nicht.

Zitat:

Zitat von himitsu
PS: Die Zugriffsprobleme, welche du beim Lesen hast, hat das andere Programm auch,
also wenn du grad dabei bist die Datei auszulesen und das andere Programm da grad was reinschreiben will ... *peng* und, wenn du Pech hast, das andere Programm macht sonstwas :stupid:

ich dachte Filesystem Zugriffe werden durch Windows Threadsafe gemacht. :gruebel:

Zitat:

Zitat von Morphie
Du könntest einfach die Datei temporär kopieren, dann sollte das doch eigentlich klappen, oder?
müsstest du beim FTP ja sowieso, oder?

Davon abgesehen das ich auch nicht auf die Datei zugreifen kann um sie kopieren zu können, ist dies bei teilweiße großen Logs über das Netzwerk eine sehr schlechte Lösung.

Das mit dem FTP ist sehr optional und war nur mal eine kleine Idee von mir. Also kann dies erstmal nach hinten gestellt werden.

himitsu 22. Sep 2009 17:32

Re: Tail Funktionalität
 
Zitat:

ich dachte Filesystem Zugriffe werden durch Windows Threadsafe gemacht.
jupp, so wie du jetzt Probleme mit dem Zugriff hast, da der Service die Datei gerade offen hat,
wird dieser dann Problme bekommen, wenn er zugreifen will und die Datei grad von dir gegöffnet ist.

leider weiß man nie genau, wie fremde Programme bei Fehlern so reagieren, bzw ob der entsprechende Programmierer diese Fehler überhaupt abgfängt und entsprechend handelt.

gsh 22. Sep 2009 20:20

Re: Tail Funktionalität
 
Zitat:

Zitat von himitsu
Zitat:

ich dachte Filesystem Zugriffe werden durch Windows Threadsafe gemacht.
jupp, so wie du jetzt Probleme mit dem Zugriff hast, da der Service die Datei gerade offen hat,
wird dieser dann Problme bekommen, wenn er zugreifen will und die Datei grad von dir gegöffnet ist.

leider weiß man nie genau, wie fremde Programme bei Fehlern so reagieren, bzw ob der entsprechende Programmierer diese Fehler überhaupt abgfängt und entsprechend handelt.

hmm also mit WinTail hatte ich bis jetzt noch keine Probleme. Warum funktioniert das bei WinTail so Problemlos? Habe gerade bemerkt das notepad, plainedit und sogar Firefox die Datei öffnen kann. Nur Dreamweaver meldete einen Zugriffsfehler.
Jemand eine ahnung warum diese Programm es können?

mkinzler 22. Sep 2009 20:31

Re: Tail Funktionalität
 
Diese werden nicht versuchen, die Datei exklusiv zu öffnen

gsh 22. Sep 2009 20:50

Re: Tail Funktionalität
 
Zitat:

Zitat von mkinzler
Diese werden nicht versuchen, die Datei exklusiv zu öffnen

Mach ich doch auch nicht :gruebel:

Delphi-Quellcode:
S := TFileStream.Create(FileName, fmOpenRead ,fmShareDenyNone);

thkerkmann 22. Sep 2009 21:34

Re: Tail Funktionalität
 
So:

Delphi-Quellcode:
S := TFileStream.Create(FileName, fmOpenRead OR fmShareDenyNone);
sollte es aussehen.

gsh 22. Sep 2009 21:39

Re: Tail Funktionalität
 
hmm da hast du recht. hab das einfach aus Post #3 kopiert.

Funktioniert aber auch mit einem OR nicht :(

sx2008 22. Sep 2009 22:16

Re: Tail Funktionalität
 
Wenn man eine Datei öffnet kann man Sharing-Flags angeben:
a) andere Prozesse dürfen Lesen & Schreiben
b) andere Prozesse dürfen nur Lesen
c) andere Prozesse dürfen nur Schreiben (eher ungewöhnlich)
d) andere Prozesse dürfen gar nichts (Exclusiv Modus)
Der Begriff "andere Prozesse" ist etwas ungenau: man kann die gleiche Datei auch mehr als einmal öffnen und hat dann den gleichen Status wie fremde Prozesse.
Ausserdem muss man angeben, ob man die Datei lesen/schreiben oder beides möchte.
Wenn der Dateiersteller die Variante c) oder d) wählt, dann kann die Datei von niemand anderem gelesen werden, solange sie noch im Zugriff ist.
Wenn das Öffnen wie in Betrag #15 versagt, hat man einfach Pech gehabt weil einer der anderen beteiligten Prozesse (in aller Regel der Dateiersteller) das Lesen nicht zulässt.
Man müsste schon die Sperren des Betriebssystems umgehen, um da dran zu kommen.

gsh 22. Sep 2009 23:04

Re: Tail Funktionalität
 
Zitat:

Zitat von sx2008
Wenn man eine Datei öffnet kann man Sharing-Flags angeben:
a) andere Prozesse dürfen Lesen & Schreiben
b) andere Prozesse dürfen nur Lesen
c) andere Prozesse dürfen nur Schreiben (eher ungewöhnlich)
d) andere Prozesse dürfen gar nichts (Exclusiv Modus)
Der Begriff "andere Prozesse" ist etwas ungenau: man kann die gleiche Datei auch mehr als einmal öffnen und hat dann den gleichen Status wie fremde Prozesse.
Ausserdem muss man angeben, ob man die Datei lesen/schreiben oder beides möchte.
Wenn der Dateiersteller die Variante c) oder d) wählt, dann kann die Datei von niemand anderem gelesen werden, solange sie noch im Zugriff ist.
Wenn das Öffnen wie in Betrag #15 versagt, hat man einfach Pech gehabt weil einer der anderen beteiligten Prozesse (in aller Regel der Dateiersteller) das Lesen nicht zulässt.
Man müsste schon die Sperren des Betriebssystems umgehen, um da dran zu kommen.

Hab das noch mal getestet und bin drauf gekommen das ich vorhin einen kleinen Fehler gemacht habe.
Die Datei wird vom Service nicht mit einem Filestream sondern so aufgemacht:
Delphi-Quellcode:
AssignFile(vFileHandle, vAktLogFilename);
if FileExists(vAktLogFilename) then Append(vFileHandle)
else Rewrite(vFileHandle);
Warum funktioniert meine Tail funktion bei dem nicht?
Mit Notepad und so bekomme ich sie ja auch auf.
Mit welchen "Rechten" wird die Datei bei der obrigen function aufgemacht?

Klaus01 23. Sep 2009 08:00

Re: Tail Funktionalität
 
Guten Morgen,

ein Blick in die Delphi Hilfe sagt uns:

append : a file is opened with write-only access
rewrite : if F is a text file, F becomes write-only

Ich denke mal das die "alten" Routinen die Datei exclusiv öffnen.

Kannst Du nur mal zum Spass prüfen, ob eine TStringList die Datei lesen kann?

Grüße
Klaus

gsh 23. Sep 2009 08:35

Re: Tail Funktionalität
 
Zitat:

Zitat von Klaus01
Ich denke mal das die "alten" Routinen die Datei exclusiv öffnen.

Kannst Du nur mal zum Spass prüfen, ob eine TStringList die Datei lesen kann?

Hier das Ergebnis vom TStringList test:

Zitat:

Im Projekt Project1.exe ist eine Exception der Klasse EFOpenError mit der Meldung 'Datei C:\Testlogdatei.log kann nicht geöffnet werden. Der Prozess kann nicht auf die Datei zugreifen, da sie von einem anderen Prozess verwendet wird' aufgetreten.

himitsu 23. Sep 2009 08:35

Re: Tail Funktionalität
 
Zitat:

Zitat von Klaus01
Ich denke mal das die "alten" Routinen die Datei exclusiv öffnen.

Jupp, damals hat man einfach vergessen die Sharing-Rechte zu vergeben und per Default ist alles blockiert.

Bei TFileStream kann man diese Rechte selber vergeben.

gsh 23. Sep 2009 08:37

Re: Tail Funktionalität
 
Zitat:

Zitat von himitsu
Zitat:

Zitat von Klaus01
Ich denke mal das die "alten" Routinen die Datei exclusiv öffnen.

Jupp, damals hat man einfach vergessen die Sharing-Rechte zu vergeben und per Default ist alles blockiert.

Bei TFileStream kann man diese Rechte selber vergeben.

Also ein fmShareExclusive sozusagen.
Aber warum können dann andere Anwendung das File öffnen?

himitsu 23. Sep 2009 08:56

Re: Tail Funktionalität
 
OK, hab grad nochmal nachgesehn, FILE_SHARE_READ wird doch gesetzt, also lesend kann man zugreifen.

eventuell ist ja was mit dem fmShareDenyNone nicht in Ordnung :gruebel:


OK, wenn man sich das (in D7) man ansieht, dann wird Rights einfach ignoriert, wenn man die Datei nicht selber ERSTELLT.
Delphi-Quellcode:
constructor TFileStream.Create(const FileName: string; Mode: Word; Rights: Cardinal);
begin
  if Mode = fmCreate then
  begin
    inherited Create(FileCreate(FileName, Rights));
    if FHandle < 0 then
      raise EFCreateError.CreateResFmt(@SFCreateErrorEx, [ExpandFileName(FileName), SysErrorMessage(GetLastError)]);
  end
  else
  begin
    inherited Create(FileOpen(FileName, Mode));
    if FHandle < 0 then
      raise EFOpenError.CreateResFmt(@SFOpenErrorEx, [ExpandFileName(FileName),   SysErrorMessage(GetLastError)]);
  end;
end;
[edit]
*weitersuch* gut, in FileOpen wird es aus Mode extrahiert, also eigentlich sollte es da klappen :gruebel:
fmCreate > Sharing in Rights angeben
ansonsten > Sharing mit Mode or-Verknüpfen

Wer ist nur auf diesen SCH*** gekommmen (OK, wenn man fmCreate ansieht, welches $FFFF ist, dann kann man damit nix verknüpfen, aber dennoch ... dann halt immer über Rights)
Delphi-Quellcode:
function FileOpen(const FileName: string; Mode: LongWord): Integer;
{$IFDEF MSWINDOWS}
const
  AccessMode: array[0..2] of LongWord = (
    GENERIC_READ,
    GENERIC_WRITE,
    GENERIC_READ or GENERIC_WRITE);
  ShareMode: array[0..4] of LongWord = (
    0,
    0,
    FILE_SHARE_READ,
    FILE_SHARE_WRITE,
    FILE_SHARE_READ or FILE_SHARE_WRITE);
zum Glück nutze ich diesen Stream nie und gehe fast immer direkt über die WinAPU und hatte da noch keine Probleme :angel2:

gsh 23. Sep 2009 09:08

Re: Tail Funktionalität
 
Zitat:

Zitat von himitsu
eventuell ist ja was mit dem fmShareDenyNone nicht in Ordnung :gruebel:

Hab jetzt testweiße eine Datei mit: FS := TFileStream.Create('C:\test.txt', fmOpenReadWrite or fmShareDenyWrite); blockiert.
In diesem Fall konnte ich sie mit S := TFileStream.Create('C:\test.txt', fmOpenRead or fmShareDenyNone); ohne Probleme auslesen.

Klaus01 23. Sep 2009 09:09

Re: Tail Funktionalität
 
.. dann könnte man eventuell noch

FileOpen:
Zitat:

Opens a specified file using a specified access mode.

Unit
SysUtils

Syntax
Delphi-Quellcode:
 function FileOpen(const FileName: string; Mode: Cardinal): Integer;

FileRead:
Zitat:

Reads a specified number of bytes from a file.
Unit
SysUtils
Syntax
Delphi-Quellcode:
 function FileRead(Handle: Integer; var Buffer: Type; Count: Cardinal): Integer;

ausprobieren.

Grüße
Klaus

gsh 23. Sep 2009 09:55

Re: Tail Funktionalität
 
Wenn ich das richtig verstanden habe dann wird aber FileOpen und FileReads doch eh von TFileStream aufgerufen oder?

Klaus01 23. Sep 2009 10:37

Re: Tail Funktionalität
 
Hiermit habe ich eine Datei erstellt und blockiert:
Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
begin
  assignFile(f,ExtractFilePath(ParamStr(0))+'test.txt');
  rewrite(f);
  while true do
    begin
      writeLn(f,'test test test test test test test test');
      application.processMessages;

    end;
end;
Hiermit kann ich aus der Datei lesen:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  fileHandle : Cardinal;
  buff: array[0..10] of char;
  i: Integer;
begin
  fileHandle := fileOpen(ExtractFilePath(ParamStr(0))+'test.txt',fmOpenRead or fmShareDenyNone);
  i:=fileRead(fileHandle,buff[0],length(buff));
  closeFile(fileHandle);
  edit1.Text:=buff+' '+IntToStr(i);
end;

Grüße
Klaus

gsh 23. Sep 2009 16:54

Re: Tail Funktionalität
 
Danke für deinen Test. Dein Beispiel funktioniert bei mir auch.
Aber eins verstehe ich nicht. Die "alte" Tail function (mit FileStream) funktioniert jetzt plötzlich auch :gruebel: Eigentlich hab ich ja nichts dran geändert.

Delphi-Quellcode:
function Tail(FileName:string; Position:Integer):string;
var
  S: TStream;
  L: Integer;
begin
  S := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
  try
    S.Seek(Position, soBeginning);
    L := S.Size-Position;
    SetLength(Result, L);
    S.Read(Result[1], L);
  finally
    S.Free;
  end;
end;
Aber gut wenn es jetzt funktioniert bin ich froh. Danke an Alle :dp:


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:24 Uhr.

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