Delphi 2010 - 尝试保存日志时出现 EDirectoryNotFoundException
Delphi 2010 - EDirectoryNotFoundException when trying to save logs
我正在 Delphi 2010 年开发一个程序,它必须保存存储在 Tmemo 中的日志。我正在尝试为每天创建一个日志文件,我在其中附加了 memo.After 中的日志 我附加了文本 我清除了备忘录的内容。所以在我的应用程序的位置,我想创建一个名为 "loguri-mover_ftp" 的文件夹,我想在其中存储日志文件。例如:log_mover-ftp_2-16-2015.txt
我为此使用的代码是:
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;
因为我对我的应用程序的稳定性感兴趣,所以我在我的应用程序中启用了 MadExcept 调试器。 2 小时 12 分钟后,我收到以下错误:
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, cb237f
count : 5
exception number : 1
disassembling:
[...]
005ce40a push eax
005ce40b call -ee30 (f5e0) ; SysUtils.TEncoding.GetUTF8
005ce410 mov ecx, eax
005ce412 pop eax
005ce413 pop edx
005ce414 > call -44ad (b9f6c) ; IOUtils.TFile.AppendAllText
005ce419 775 mov eax, [ebp+8]
005ce41c mov eax, [eax+a0]
005ce422 xor edx, edx
005ce424 mov ecx, [eax]
005ce426 call dword ptr [ecx+c]
[...]
我做错了什么?
调用 AppendAllText
引发异常。如果您遵循该函数的源代码,您会发现对 InternalCheckFilePathParam
的调用,其实现如下所示:
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;
现在,Path
是您传递给 AppendAllText
的第一个参数。由于正在引发 EDirectoryNotFoundException
,我们可以得出结论,包含 Path
的目录不存在。
当然,这看起来很奇怪,因为您检查它是否存在然后创建它。我觉得看什么datetostr(now)
returns就可以解谜了。您假设使用的日期分隔符是 -
。但是如果日期分隔符是 /
呢?在这种情况下,/
将被解释为路径定界符。
解决方案是使用接受 TFormatSettings
参数的 DateToStr
重载显式指定日期分隔符。
我也不能忽略你代码中的重复。请永远不要像你那样重复魔术弦。代码应如下所示:
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);
我正在 Delphi 2010 年开发一个程序,它必须保存存储在 Tmemo 中的日志。我正在尝试为每天创建一个日志文件,我在其中附加了 memo.After 中的日志 我附加了文本 我清除了备忘录的内容。所以在我的应用程序的位置,我想创建一个名为 "loguri-mover_ftp" 的文件夹,我想在其中存储日志文件。例如:log_mover-ftp_2-16-2015.txt
我为此使用的代码是:
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;
因为我对我的应用程序的稳定性感兴趣,所以我在我的应用程序中启用了 MadExcept 调试器。 2 小时 12 分钟后,我收到以下错误:
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, cb237f
count : 5
exception number : 1
disassembling:
[...]
005ce40a push eax
005ce40b call -ee30 (f5e0) ; SysUtils.TEncoding.GetUTF8
005ce410 mov ecx, eax
005ce412 pop eax
005ce413 pop edx
005ce414 > call -44ad (b9f6c) ; IOUtils.TFile.AppendAllText
005ce419 775 mov eax, [ebp+8]
005ce41c mov eax, [eax+a0]
005ce422 xor edx, edx
005ce424 mov ecx, [eax]
005ce426 call dword ptr [ecx+c]
[...]
我做错了什么?
调用 AppendAllText
引发异常。如果您遵循该函数的源代码,您会发现对 InternalCheckFilePathParam
的调用,其实现如下所示:
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;
现在,Path
是您传递给 AppendAllText
的第一个参数。由于正在引发 EDirectoryNotFoundException
,我们可以得出结论,包含 Path
的目录不存在。
当然,这看起来很奇怪,因为您检查它是否存在然后创建它。我觉得看什么datetostr(now)
returns就可以解谜了。您假设使用的日期分隔符是 -
。但是如果日期分隔符是 /
呢?在这种情况下,/
将被解释为路径定界符。
解决方案是使用接受 TFormatSettings
参数的 DateToStr
重载显式指定日期分隔符。
我也不能忽略你代码中的重复。请永远不要像你那样重复魔术弦。代码应如下所示:
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);