Reputation: 255
I'm developing a program in Delphi 2010 that has to save the logs that are stored in a Tmemo. I'm trying to create a log file for everyday in which I append the logs from a memo.After I append the text I clear the content of the memo. So in the location of my app i want to create a folder named "loguri-mover_ftp" in which i want to store the log file. EX: log_mover-ftp_2-16-2015.txt
The code I use for this is:
If DirectoryExists(ExtractFilePath(Application.ExeName) + 'loguri-mover_ftp') then
begin
TFile.AppendAllText(ExtractFilePath(Application.ExeName) + 'loguri-mover_ftp\log_mover-ftp_' + datetostr(now) + '.txt',memo_loguri.lines.text, TEncoding.UTF8);
Memo_loguri.lines.text:='';
end
else
begin
CreateDir(ExtractFilePath(Application.ExeName) + 'loguri-mover_ftp');
TFile.AppendAllText(ExtractFilePath(Application.ExeName) + 'loguri-mover_ftp\log_mover-ftp_' + datetostr(now) + '.txt',memo_loguri.lines.text, TEncoding.UTF8);
Memo_loguri.lines.text:='';
end;
Because I'm interested in the stability of my application I've enabled the MadExcept debugger inside my app. After 2 hours 12 minutes i get the following error:
exception class : EDirectoryNotFoundException
exception message : The specified path was not found.
compiled with : Delphi 2010
program up time : 2 hours 12 minutes
madExcept version : 4.0.7
callstack crc : $bed2c7c0, $c58f696b, $05cb237f
count : 5
exception number : 1
disassembling:
[...]
005ce40a push eax
005ce40b call -$13ee30 ($48f5e0) ; SysUtils.TEncoding.GetUTF8
005ce410 mov ecx, eax
005ce412 pop eax
005ce413 pop edx
005ce414 > call -$1144ad ($4b9f6c) ; IOUtils.TFile.AppendAllText
005ce419 775 mov eax, [ebp+8]
005ce41c mov eax, [eax+$2a0]
005ce422 xor edx, edx
005ce424 mov ecx, [eax]
005ce426 call dword ptr [ecx+$2c]
[...]
What am I doing wrong?
Upvotes: 0
Views: 857
Reputation: 612963
The exception is raised by the call to AppendAllText
. If you follow the source for that function you will find a call to InternalCheckFilePathParam
, the implementation of which looks like this:
class procedure TFile.InternalCheckFilePathParam(const Path: string;
const FileExistsCheck: Boolean);
begin
if (Length(Path) >= MAX_PATH - TFile.FCMinFileNameLen) and
(not TPath.IsExtendedPrefixed(Path)) then
raise EPathTooLongException.CreateRes(@SPathTooLong);
if not TPath.HasPathValidColon(Path) then
raise ENotSupportedException.CreateRes(@SPathFormatNotSupported);
if Trim(Path) = '' then // DO NOT LOCALIZE
raise EArgumentException.CreateRes(@SInvalidCharsInPath);
if not TPath.HasValidPathChars(Path, False) then
raise EArgumentException.CreateRes(@SInvalidCharsInPath);
if not TDirectory.Exists(TPath.DoGetDirectoryName(TPath.DoGetFullPath(Path))) then
raise EDirectoryNotFoundException.CreateRes(@SPathNotFound);
if FileExistsCheck and (not Exists(Path)) then
raise EFileNotFoundException.CreateRes(@SFileNotFound);
end;
Now, Path
is the first argument that you passed to AppendAllText
. Since EDirectoryNotFoundException
is being raised, we can conclude that the directory containing Path
does not exist.
Of course, this seems odd give that you check for its existence and then create it. I think the mystery can be solved by looking at what datetostr(now)
returns. You imagine that the date separator used is -
. But what if the date separator is /
? In that case the /
will be interpreted as a path delimiter.
The solution is to specify the date separator explicitly by using the DateToStr
overload that accepts a TFormatSettings
parameter.
I also cannot ignore the duplication in your code. Please don't ever repeat magic strings the way you do. The code should look like this:
LogFileDir := TPath.Combine(ExtractFilePath(Application.ExeName), 'loguri-mover_ftp');
if not DirectoryExists(LogFileDir) then
ForceDirectories(LogFileDir);
DateStr := DateToStr(Now, ...); // you supply an appropriate TFormatSettings
LogFilePath := TPath.Combine(LogFileDir, log_mover-ftp_' + DateStr + '.txt');
TFile.AppendAllText(LogFilePath, memo_loguri.lines.text, TEncoding.UTF8);
Upvotes: 1