简体   繁体   中英

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.

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.

There are several things that I'd change about your code.

  1. You've got a function that's supposed to return a boolean, but you never set a return value.

  2. It's not "wrong", but variable i is most commonly used as an integer index to an array, or as a loop variable. Delphi developers are going to hate code that uses i as a string.

  3. It looks like you're just logging text. TFileStream is probably not the best class to do that.

I think this is much cleaner code:

uses System.IoUtils;

...

FileName := 'log.txt';
LogLine  := 'Boss is dead '+TimeToStr(Now);

TFile.AppendAllText(FileName, LogLine);

http://docwiki.embarcadero.com/Libraries/XE7/en/System.IOUtils.TFile.AppendAllText

How about this:

uses SysUtils;

var s: AnsiString;

s := FormatDateTime('yyyy-mm-dd hh:nn:ss', now);
fs.Write(s[1], Length(s));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM