在我的几个应用程序中,我的代码类似于以下内容:
if ForceDirectories(ExtractFilePath(lLogName)) then
begin
AssignFile(lLog, lLogName);
try
if FileExists(lLogName) then
Append(lLog)
else
Rewrite(lLog);
Writeln(lLog, lLogLine);
finally
{$I-}CloseFile(lLog);{$I+}
end;
end;
Run Code Online (Sandbox Code Playgroud)
在一个应用程序中,第一次尝试执行此操作时,我一直在使用Append语句的行上获得I/O错误103异常(在调用此文件之前文件确实存在).此操作的所有后续尝试都将正常工作 - 直到我重新启动应用程序.
所有我发现这个错误的文档到目前为止表示,这将通过调用引起CloseFile恕不另行Reset或者Rewrite(Append通常没有提及),或者如果该文件是由另一个进程使用.由于异常发生在调用CloseFile它之前显然不可能是前者.
我已经尝试Reset在AssignFilefor good措施之后插入一个权利,但之后我在该行上获得了异常.
也没有其他应用程序直接访问该文件.我说的"阳谋",因为我有一个轻微的怀疑,防病毒(TrendMicro的在我的情况)可能是cuplrit这里(所以也许该文件是在使用中).如果这确实是问题,那么围绕它的最佳方法是什么?硬编码自动重试对我来说真的不是一个干净的解决方案......
在那里我有时会收到103错误另一种情况是这样的代码,我用它来创建一个空文件(或者更经常清空现有的文件):
AssignFile(lFile, AFileName);
try
Rewrite(lFile);
finally
CloseFile(lFile);
end;
Run Code Online (Sandbox Code Playgroud)
在这种情况下,重现起来要困难得多.它发生的次数要少得多.大多数情况下,这似乎是在我重新编译应用程序后的第一次运行时发生的.这可能再次成为反病毒的阻碍吗?我从未见过这种情况发生在我的开发机器上,从未得到过客户的报告.与第一个场景一样,每个应用程序会话只发生一次(如果有的话).后续尝试总是成功的.
有关创建空文件或清空现有文件的其他可能更安全的故障安全方法的建议吗?
小智 12
好吧,这已经晚了一年多了,但是我要加上我的评论,因为它解释了为什么会发生这种情况.
我在多线程应用程序,代码几乎相同于上述片段有完全相同的问题,我有保护代码的关键部分.
当一个记录操作迅速跟随另一个时,问题最容易发生.由于上述原因,第二次操作将失败.
我以为它也是防病毒软件,但错误发生在一台机器而不是另一台机器上,两者都安装了Norton 360.有问题的机器是全新的Windows 7和没有Windows XP的机器.一位同事也遇到了在虚拟化Windows Vista机器下运行系统的问题,没有安装病毒检查程序.
所以我的问题是,"为什么这台XP机器如此不同?".
首先,它不是处女,这似乎是答案:
机会锁定和NT缓存被关闭.大多数(成熟的)Delphi开发人员都知道,在使用BDE时,这些是关闭的,以便在多用户情况下维护DBF和DB文件的完整性.在较新的机器上未禁用这些设置,因为我们不再为Paradox数据文件开发!
延迟写入缓存似乎在文件上留下读/写锁,直到操作系统完成其业务,这可能是几毫秒之后.
因此,在我的情况下,第二个日志事件被第一个阻止.
好吧,我并不是说你关掉机会锁定+ NT缓存.我们摆脱BDE的一个主要原因是避免说服客户修改这些设置.因此,有四种实用的解决方案:
1)如dangph所述,重试一段可接受的时间.
2)在应用程序加载时打开文件,并在应用程序的整个持续时间内保持打开状态.如果您正在运行应用程序的多个实例,则不太有用.
3)懒惰地在日志代码之前放置一个sleep(1)并希望它足够长以释放锁.但是,如果您进行大量日志记录,则可能会降低系统速度.
或者4)试试......除了你的代码.但是你可能会保证错过100%的第二条消息(指我的情况).
我不明白自动重试有什么问题。我不认为你还能做任何其他事情。如果其他进程正在读取该文件,那么您的追加/重写将会失败。由于该文件是日志,因此很有可能在您尝试打开它时某些东西(例如日志查看器或文本编辑器)会读取它。
尝试打开该文件几次,尝试之间有一定的延迟,然后再彻底失败。如果你想变得更奇特,你可以使用指数退避。