Delphi - tfilestream: записать время и дату в файл

Я пытаюсь сохранить строку для каждого события, содержащую фрагмент текста и время + дату, когда произошло.

Проблема в:

  1. время показывается китайским шрифтом
  2. он заменяет одну и ту же строку снова и снова

Вот код:

    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;

Спасибо.

3 ответа

Решение

Обычно, когда вы ожидаете текст на латинице, но видите текст на китайском языке, это означает, что вы интерпретируете текст ANSI, как если бы он был UTF-16. Из этого я делаю вывод, что вы намерены записать текст UTF-16, но на самом деле пишете текст ANSI. Это означает, что у вас есть Delphi до Unicode.

Что касается того, почему вы продолжаете перезаписывать файл, то это потому, что вы передаете fmCreate, Что вы действительно хотите сделать, так это открыть существующий файл в режиме записи или, если файл не существует, создать новый файл. Функция Win32 API поддерживает это с OPEN_ALWAYS творческий нрав. Но это не доступно через TFileStream.Create, Так что вы должны использовать THandleStream и позвонить CreateFile непосредственно. Обратите внимание, что более новые версии Delphi представляют TFile.Open что разоблачает OPEN_ALWAYS функциональность. Но мои рассуждения говорят, что вы используете Delphi, который слишком стар.

Предполагая, что вы можете использовать THandleStreamи позвоните CreateFile правильно, тогда вам просто нужно выписать текст UTF-16. Самый простой способ - это использовать WideString, Вы можете написать код так:

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

С другой стороны, возможно, китайцы пришли отсюда:

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

Этот код просто записывает указатель на файл. Вы точно не хотите этого делать и должны удалить эту строку. Для полноты картины, если у вас есть Unicode Delphi, вы бы написали текст очень похожим образом. Как это:

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

Возвращаясь к добавлению в поток, он будет работать так:

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;

Наконец, я должен был сделать много предположений о вашей среде в этом ответе. В будущем всегда включайте версию Delphi, которую вы используете. И всегда включайте четкое изложение ваших целей.

Как насчет этого:

uses SysUtils;

var s: AnsiString;

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

Есть несколько вещей, которые я бы изменил в вашем коде.

  1. У вас есть функция, которая должна возвращать логическое значение, но вы никогда не устанавливаете возвращаемое значение.

  2. Это не "неправильно", а переменная i чаще всего используется как целочисленный индекс для массива или как переменная цикла. Разработчики Delphi будут ненавидеть код, который использует i как строка

  3. Похоже, вы просто записываете текст. TFileStream, вероятно, не лучший класс для этого.

Я думаю, что это намного чище код:

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

Другие вопросы по тегам