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);