Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Windows API: FindFirstFile absolute path vs current directory

1,867 views
Skip to first unread message

Andrew Tomazos

unread,
Mar 13, 2009, 8:21:42 PM3/13/09
to
I want to find files that have absolute paths that match a given
prefix. The problem with using FindFirstFile is that it will not only
find absolute paths, but it will also match files in the current
working directory of the process.

Can anyone think of a clean strategy to filter out matches from the
current working directory?

I suppose I could just create a temporary empty directory and change
the working directory into it, but I would prefer to leave the working
directory untouched in case it is being used elsewhere in the process.
-Andrew.

Grinder

unread,
Mar 13, 2009, 10:00:23 PM3/13/09
to
Andrew Tomazos wrote:
> I want to find files that have absolute paths that match a given
> prefix. The problem with using FindFirstFile is that it will not only
> find absolute paths, but it will also match files in the current
> working directory of the process.

Wow, really? I can't reproduce that here. Can you show your code?

> Can anyone think of a clean strategy to filter out matches from the
> current working directory?
>
> I suppose I could just create a temporary empty directory and change
> the working directory into it, but I would prefer to leave the working
> directory untouched in case it is being used elsewhere in the process.

Here's my Delphi code:

program Tomazos;

{$APPTYPE CONSOLE}

uses
SysUtils, Windows;

var
sFind : string;
hFind : LongWord;
rFind : WIN32_FIND_DATA;
sFile : string;
begin
WriteLn('Current Directory: ' + ExpandFileName('.'));

// search the target directory
sFind := 'D:\Users\Grinder\My Documents\*.xls';
WriteLn;
WriteLn('Find: ' + sFind);

hFind := FindFirstFile(PChar(sFind), rFind);
if hFind <> INVALID_HANDLE_VALUE then
begin
repeat
sFile := rFind.cFileName;
WriteLn(sFile);
until not FindNextFile(hFind, rFind);
end;

// search the current directory for comparison
sFind := ExpandFileName('.') + '\*.xls';
WriteLn;
WriteLn('Find: ' + sFind);

hFind := FindFirstFile(PChar(sFind), rFind);
if hFind <> INVALID_HANDLE_VALUE then
begin
repeat
sFile := rFind.cFileName;
WriteLn(sFile);
until not FindNextFile(hFind, rFind);
end;
end.

Here are the results that I get:

Current Directory: D:\Users\Grinder\Desktop

Find: D:\Users\Grinder\My Documents\*.xls
ISP.xls
Truck Odometer.xls

Find: D:\Users\Grinder\Desktop\*.xls
Arcade Classics.xls
LCD Monitor vs TV.xls
MythTV Keys.xls

Andrew Tomazos

unread,
Mar 13, 2009, 11:14:32 PM3/13/09
to
On Mar 14, 3:00 am, Grinder <grin...@no.spam.maam.com> wrote:
> Andrew Tomazos wrote:
> > I want to find files that have absolute paths that match a given
> > prefix.  The problem with using FindFirstFile is that it will not only
> > find absolute paths, but it will also match files in the current
> > working directory of the process.
>
> Wow, really?  I can't reproduce that here.  Can you show your code?
>
>      // search the target directory
>      sFind := 'D:\Users\Grinder\My Documents\*.xls';
>      WriteLn;

Change your code as follows:

- sFind := 'D:\Users\Grinder\My Documents\*.xls';
+ sFind := 'A*';

Now FindFirstFile will return everything in the current working
directory of the process that starts with the letter A.
-Andrew.

Grinder

unread,
Mar 13, 2009, 11:53:39 PM3/13/09
to

I thought the problem was that Find*File was finding files in an
absolute path *and* in the current directory, when you only wanted the
files in the absolute path.

If that's not it, what is the problem?

Jaelani

unread,
Mar 14, 2009, 7:11:28 AM3/14/09
to

Passing a relative path to the FindFirstFile will always search the
current directory. If you can only pass the path as relative one, change
the current directory prior calling FindFirstFile.

Andrew Tomazos

unread,
Mar 14, 2009, 11:53:32 AM3/14/09
to
Grinder wrote:
>I thought the problem was that Find*File was finding files in an
>absolute path *and* in the current directory, when you only wanted the
>files in the absolute path.

>If that's not it, what is the problem?

Jaelani wrote:
> Passing a relative path to the FindFirstFile will always search the
> current directory. If you can only pass the path as relative one, change
> the current directory prior calling FindFirstFile.

Ok, let me restate the question:

Given an arbitrary string s, determine whether s is potentially the
prefix of an absolute path, a relative path or both.

For example "C:\a", "\\myserver\foo", "\\?\{Volume 3" are all prefixes
of absolute paths and definately not relative paths.

"foo\bar" is definitely a prefix of a relative path.

"a" is potentially either an absolute path ("a:\foo") or a relative
path ("aardvark\boo")

What is the cleanest way of making this determination of string s? It
would be nice not to have to iterate through all the possible path
forms of all possible filesystems.

Here is my thought on this, but it is very ugly:

bool bAbsolutePath = ( (s.length() > 1 && (s[0] == '\\' || s[1] ==
':') ) || (s.length() == 1 && (s[0] element of logical drive list)) ||
s.length() == 0

Regards,
Andrew.

Grinder

unread,
Mar 14, 2009, 3:56:48 PM3/14/09
to

Ok, this doesn't seem to be related to FindFirstFile at all anymore.

I can't recall really needing to know if a given path was relative or
absolute. If I have to insure that a given path /is/ absolute, I just
use GetFullPathName. (Or, ExpandFileName in Delphi which relies upon
GetFullPathName.)

I'm not sure why you would qualify a zero-lengthed string as an absolute
path, but that's just semantics. It's really a tri-state: absolute
path, relative path, or not a path at all. You've noticed, though, that
would be a giant ass pain to implement for every filesystem.

Jaelani

unread,
Mar 14, 2009, 4:17:30 PM3/14/09
to
Andrew Tomazos wrote:
> For example "C:\a", "\\myserver\foo", "\\?\{Volume 3" are all prefixes
> of absolute paths and definately not relative paths.
>
> "foo\bar" is definitely a prefix of a relative path.

Both are true.


> "a" is potentially either an absolute path ("a:\foo") or a relative
> path ("aardvark\boo")

Half true. "a" is a relative path and not a valid drive letter based
path. Drive letter based path must be a letter followed by a colon (":")
character. Drive letter also can not be specified as a wildcard
character. e.g. "?:\foo". This is invalid.


Absolute paths have these characteristics.
Length is at least 2 characters, AND
( Second character is ":", OR First two characters is "\\" )

The above characteristics apply for:
- Drive letter based paths.
- UNC paths.
- Unicode paths (includes all of the above and volume based paths).

Validating whether a path is valid IS a different matter. The
FindFirstFile function handles it all. So no need to do a pre-check on
the drive letter against a list of available drive letters in the system.

Quick checking a path can be done by retrieving its attribute using
GetFileAttributes but the path must not contains any wildcard.

r_z_...@pen_fact.com

unread,
Mar 16, 2009, 3:15:48 PM3/16/09
to
On Sat, 14 Mar 2009 19:56:48 GMT, Grinder <gri...@no.spam.maam.com>
wrote:

>
>I can't recall really needing to know if a given path was relative or
>absolute. If I have to insure that a given path /is/ absolute, I just
>use GetFullPathName. (Or, ExpandFileName in Delphi which relies upon
>GetFullPathName.)

FWIW: GetFullPathName is not available for, at least older version of,
Windows CE.

-----------------------------------------
To reply to me, remove the underscores (_) from my email address (and please indicate which newsgroup and message).

Robert E. Zaret, eMVP
PenFact, Inc.
20 Park Plaza, Suite 400
Boston, MA 02116
www.penfact.com
Useful reading (be sure to read its disclaimer first):
http://catb.org/~esr/faqs/smart-questions.html

0 new messages