Search code examples
delphidelphi-7

FileExists returns true but file doesn't exist


I write my program in Delphi 7. I only need it to work on non-Unicode filenames. If it finds a Unicode filename it should just ignore it.

My code looks like this:

var Filename: String;

if not FileExists(Filename) then Exit;

F := TFileStream(Filename, fmOpenRead or fmShareDenyWrite);

However in case of some Unicode filenames the FileExists() returns true but then TFileStream raises an exception because the path is invalid.

For example: A file named: "loop 輪紋.jpg" is read into Filename as "loop ??.jpg". This is expected behavior. TFileStream cannot read such file (because there is no "loop ??.jpg" in the directory) and raises an exception. But FileExists() should catch that this file doesn't exist. Why it doesn't work? Because it is defined as:

function FileExists(const FileName: string): Boolean;
begin
  Result := FileAge(FileName) <> -1;
end;

and FileAge() is defined as:

function FileAge(const FileName: string): Integer;
var
  Handle: THandle;
  FindData: TWin32FindData;
  LocalFileTime: TFileTime;
begin
  Handle := FindFirstFile(PChar(FileName), FindData);
...

FindFirstFile uses "loop ??.jpg" as a mask and then finds "loop 輪紋.jpg".

So the question is eiter:

1) Can I in Delphi 7 somehow easily use Unicode filenames in TFileStream?

or

2) What function should I use instead of FileExists to get correct results?


Solution

    1. Not with TFileStream itself, no. But you can instead use the Win32 CreateFileW() to open the Unicode filename, and then assign the returned HANDLE to a THandleStream. That is essentially what TFileStream does internally (using CreateFileA() instead in Delphi 7).

    2. Later versions of Delphi use the Win32 GetFileAttributes() 1 instead of the RTL's FileAge() in their implementation of FileExists(). GetFileAttributes() does not support wildcards, like FindFirstFile() does.

      1. See Why is GetFileAttributes the way old-timers test file existence?

    Or, you could simply not check for file existence at all before opening the file, just open it unconditionally and catch the resulting error. The OS will tell you whether the failure is due to the file not being found vs some other error.