Delphi/Turbo Pascal: AppendWithRetry for text files to retry Append
Posted by jpluimers on 2014/03/10
Every once in a while you have multiple threads or processes wanting to write a short message to the same log file. Append then will give you an I/O error 32 (ERROR_SHARING_VIOLATION), but the below small routine will sleep a bit while retrying a couple of times.
It uses these Delphi aspects around the $I or $IOCHECKS compiler directive:
- in $I+ mode, you get exceptions when certain “classic” Pascal style I/O operations fail.
- in $I- mode, you access the IOResult to obtain the results of those I/O operations
- IOResult gets the result of the last failed operation (if any) or zero if none failed
- IOResult clears the underlying storage to zero
- $IFOPT checks for a certain state of a compiler flag
- You can store the state of $OPT in a temporary conditional define
Note there are a few tables of codes you can get back through IOResult as basically you can get many GetLastError results in IOResult as well:
- System.IOResult – RAD Studio API Documentation.
- System Error Codes (0-499) (Windows).
- 2.2 Win32 Error Codes.
I wish Embarcadero had done things like this to prevent Delphi IDE startup messages like these:
[RAD Studio]
The imported project file could not be loaded. The process cannot access the file ‘C:\Users\Developer\AppData\Roaming\Embarcadero\BDS\10.0\environment.proj’ because it is being used by another process. C:\Users\Developer\AppData\Roaming\Embarcadero\BDS\10.0\environment.proj.
[OK]
Anyway, here is the code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//1 do not use 0=aSleepMillisecondsBetweenRetries as Sleep doesn't work predictably then: http://blogs.msdn.com/b/oldnewthing/archive/2005/10/04/476847.aspx | |
function AppendWithRetry(const aTextFile: TextFile; const aRetryCount: Integer = 10; const aSleepMillisecondsBetweenRetries: Integer = 1): Boolean; | |
var | |
lCount: Integer; | |
lIOResult: Integer; | |
begin | |
Result := False; | |
{$IFOPT I+} | |
{$DEFINE AppendWithRetry_IPlus} | |
{$I-} | |
{$ENDIF I+} | |
lIOResult := 0; | |
lCount := aRetryCount; | |
while lCount > 0 do | |
begin | |
Append(aTextFile); | |
lIOResult := IOResult; | |
if lIOResult = 0 then | |
begin | |
lCount := -1; // no more tries needed | |
Result := True; | |
end | |
else | |
begin | |
Sleep(aSleepMillisecondsBetweenRetries); | |
Dec(lCount); | |
end; | |
end; | |
{$IFDEF AppendWithRetry_IPlus} | |
{$I+} | |
if lCount = 0 then | |
begin // retry once more to see if we can still force a run-time-error | |
Append(aTextFile); // retry once more | |
Result := True; // when there was no I/O error, otherwise an exception gets thrown. | |
end; | |
{$ENDIF AppendWithRetry_IPlus} | |
end; |
–jeroen
via:
uligerhardt said
I’m surprised that you haven’t been chastised yet for publicly mentioning old skool IO. :-)
jpluimers said
I’m from the pre-internet Era (: