Delphi: Why do I sometimes get an I/O Error 103 with this code?

Okay, it's over a year late, but I'm going to add my comment to this, as it explains why this is happening.

I had the exact same problem in a multi-threaded application with code almost identical to the snippet above and I had critical sections protecting the code.

The problem occurred most readily when one logging operation swiftly followed another. The second operation would fail for the above reason.

I thought it was anti-virus software too, but the error happened on one machine and not the other, where both had Norton 360 installed. The machine with the problem was brand new Windows 7 and the one without was Windows XP. A colleague also had the problem running the system under a virtualised Windows Vista machine with no virus checker installed.

So my question was, "why was this XP machine so different?".

For one, it wasn't virgin, and that is the answer it seems:

Opportunistic locking and NT caching were turned off. Most (mature) Delphi developers will know that when using BDE, these are turned off in order to maintain DBF and DB file integrity in multi-user situations. These settings were not disabled on the newer machines because we no longer develop for Paradox data files!

Delayed write caching seems to leave a read/write lock on the file until the OS has done its business, which could be several milliseconds later.

So, in my case, the second log event was being blocked by the first.

Okay, I'm not suggesting that you turn off opportunistic locking + NT Caching. One of the major reasons we moved away from BDE was to avoid persuading customers to tinker with such settings. So, there are four practical solutions:

1) To retry for an acceptable period of time, as mentioned by dangph.

2) to open the file when the application loads and hold it open for the full duration of the application. Not so useful if you are running multiple instances of the application.

3) Lazily put a sleep(1) before the logging code and hope that is long enough for the lock to be released. But that risks slowing your system down if you are doing lots of logging.

or 4) Put a try...except..end around your code. But then you are probably guaranteed to miss 100% of the second messages (referring to my case).


You should generally put opening the file before the try of a try..finally:

if fileexists then
  append(..)
else
  rewrite(..);
try
  // do something with the file
finally
  CloseFile(..);
end;

and

AssignFile(lFile, AFileName);
Rewrite(lFile);
CloseFile(lFile);

(try finally does not make any sense in the last case)

Otherwise closing the file might fail because it could not be opened and this would mask the real error.

But I don't think that is the issue here.

Tags:

File Io

Delphi