Search code examples
delphitfilestream

Delphi - tfilestream: write time and date to file


I am trying to save a line for each event containing a piece of text and the time + date when happened.

The problem is:

  1. time is shown as Chinese font
  2. it replaces the same line over and over again

Here is the code:

    uses sysUtils, classes;

function log: Boolean;
var
  fs: TFileStream;
  i : String;
  time : TDateTime;

begin
  i := 'Boss is dead!';
  time := now;
  try
    fs := TFileStream.Create('log.txt', fmCreate or fmOpenWrite);
    fs.Write(PChar(i +TimeToStr(time))^, Length(i +TimeToStr(time)));
    fs.write(i, sizeof(i));   
  finally
    fs.Free; 
  end;

end;

Thank you.


Solution

  • Usually when you expect Latin text, but see Chinese text, that means that you are interpreting ANSI text as though it were UTF-16. From this I infer that you are intending to write out UTF-16 text, but are actually writing out ANSI text. Which means that you have a pre-Unicode Delphi.

    As far as why you keep overwriting the file, then that's because you pass fmCreate. What you really want to do is open an existing file in write mode, or if no file exists, create a new file. The Win32 API function supports that with the OPEN_ALWAYS creation disposition. But that is not available through TFileStream.Create. So you have to use THandleStream and call CreateFile directly. Note that newer versions of Delphi introduce TFile.Open that exposes OPEN_ALWAYS functionality. But my reasoning says you are using a Delphi that is too old.

    Assuming that you can use THandleStream, and call CreateFile correctly, then you just need to write out UTF-16 text. The simplest way is to use a WideString. You might write the code like this:

    var
      ws: WideString;
    ....
    Stream.Seek(0, soFromEnd);
    ws := TimeToStr(Now) + sLineBreak;
    Stream.WriteBuffer(PWideChar(ws)^, SizeOf(WideChar)*Length(ws));
    

    On the other hand, perhaps the Chinese comes from here:

    fs.write(i, sizeof(i));
    

    This code simply writes a pointer to the file. You for sure don't want to do that and should remove that line. For sake of completeness, if you do have a Unicode Delphi, then you would write the text in a quite similar way. Like this:

    var
      s: string;
    ....
    Stream.Seek(0, soFromEnd);
    s := TimeToStr(Now) + sLineBreak;
    Stream.WriteBuffer(PWideChar(s)^, SizeOf(WideChar)*Length(s));
    

    Going back to appending to a stream, that would run like this:

    var
      hFile: THandle;
    ....
    hFile := CreateFile(
      PChar(LogFileName),
      GENERIC_WRITE,
      FILE_SHARE_READ,
      nil,
      OPEN_ALWAYS,
      FILE_ATTRIBUTE_NORMAL,
      0
    );
    Win32Check(hFile<>INVALID_HANDLE_VALUE);
    Try
      Stream := THandleStream.Create(hFile);
      Try
        .... code to write to the stream goes here
      Finally
        Stream.Free;
      End;
    Finally
      CloseHandle(hFile);
    End;
    

    Finally, I have had to make a lot of guesses about your environment in this answer. In future, always include the Delphi version that you use. And always include a clear statement of your goals.