user3702997
user3702997

Reputation: 111

Delphi - Reading from a log file that changes every second

I need to read from a .log file that is constantly changing by another application. (more data being added frequently)

So I have this to begin with:

var
    LogFile: TStrings;
    Stream: TStream;
   begin
   LogFile := TStringList.Create;
   try
      Stream := TFileStream.Create(Log, fmOpenRead or fmShareDenyNone);
      try
         LogFile.LoadFromStream(Stream);
      finally
         Stream.Free;
      end;

      while LogFile.Count > Memo1.Lines.Count do
      Memo1.Lines.Add(LogFile[Memo1.Lines.Count]);
   finally
      LogFile.Free;
   end;
end;

This works perfectly fine. It updates the memo at real time with the data being added. However some of the data being added I don't want to see in the memo. I wish to not add these lines, but still have the memo updated at real time without the junk lines.

What is the best way to go about this?

Upvotes: 3

Views: 2531

Answers (3)

user3702997
user3702997

Reputation: 111

I know its been a couple of weeks since i last posted here, but i rewrote the entire application and came up with this piece of code, which is working perfectly!

Basically i do not call .free on the stream or stringlist and am able to set the initial stream size then check if its changed, hence getting the data i need and not the entire file!

Thanks everyone for helping!

procedure TForm1.GetEndLogFile;
begin
  LogFile := TStringList.Create;
  Stream := TFileStream.Create('C:\Users\John\Documents\chat.log', fmOpenRead or fmShareDenyNone);
  LogFile.LoadFromStream(Stream);
  i := Stream.Size;
end;

procedure TForm1.LogFileRefresh;
var
  buf: string;
begin
  if i <> Stream.Size then
  begin
    SetLength(buf, Stream.Size);
    Stream.Seek(i, Stream.Size);
    Stream.Read(buf[1], Stream.Size);
    i := Stream.Size;
    Memo1.Lines.Append(Buf);
    //ShowMessage(buf);
  end;
end;

Upvotes: 1

Ken White
Ken White

Reputation: 125728

You'd clearly need to check to see if the line has content you want to include, and only add it if it has that content (or not add it if you don't want to include it, whichever is the case). It would also be much more efficient to keep track of the last line in the LogFile you processed previously, so you could skip those lines each time - if you make the variable a private member of the form itself, it will automatically be initialized to 0 when your application starts:

type
  TForm1 = class(TForm)
    //... other stuff added by IDE
  private
    LastLine: Integer;
  end;


// At the point you need to add the logfile to the memo
for i := LastLine to LogFile.Count - 1 do
begin
  if ContentWanted(LogFile[i]) then
    Memo1.Lines.Append(LogFile[i]);
  Inc(LastLine);
end;

So to handle this completely based on your code:

type
  TForm1 = class(TForm)
    //... IDE stuff here
  private
    FLastLogLine: Integer;
    procedure ProcessLogFile;
  public
    // Other stuff
  end;

procedure TForm1.ProcessLogFile;
var
  Log: TStringList;
  LogStream: TFileStream;
  i: Integer;
begin
  Log := TStringList.Create;
  try
    LogStream := TFileStream.Create(...);
    try
      Log.LoadFromStream(LogStream);
    finally
      LogStream.Free;
    end;

    for i := FLastLogLine to Log.Count - 1 do
      if Pos('[Globals] []', Log[i]) <>0 then
        Memo1.Lines.Append(Log[i]);

    // We've now processed all the lines in Log. Save
    // the last line we processed as the starting point
    // for the next pass.
    FLastLogLine := Log.Count - 1;      
  finally
    Log.Free;
  end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;
  try
    ProcessLogFile;
  finally
    Timer1.Enabled := True;
  end;
end;
end;

Upvotes: 6

user3702997
user3702997

Reputation: 111

procedure TForm1.GetEndLogFile;
var
  LogFile: TStrings;
  Stream: TStream;
begin
  LogFile := TStringList.Create;
  try
    Stream := TFileStream.Create(LogFile, fmOpenRead or fmShareDenyNone);
    try
      LogFile.LoadFromStream(Stream);
      EndOfFile := LogFile.Count;
    finally
      Stream.Free;
    end;
  finally
    LogFile.Free;
  end;
end;

procedure TForm1.LogFileRefresh;
var
  LogFile2: TStrings;
  Stream2: TStream;
  i: Integer;
begin
  LogFile2 := TStringList.Create;
  try
    Stream2 := TFileStream.Create(LogFile, fmOpenRead or fmShareDenyNone);
    try
      LogFile2.LoadFromStream(Stream2);
    finally
      Stream2.Free;
    end;
    for i := EndOfFile to LogFile2.Count -1 do
    begin
      if Pos('[Globals] []',LogFile2[i])<>0 then
      Memo1.Lines.Append(LogFile2[i]);
      Inc(EndOfFile);
    end;
  finally
    LogFile2.Free
  end;
end;

Basically came up with this, and its working perfectly fine. Should i run into any problems this way? Is there a neater way to do this?

Upvotes: 0

Related Questions