Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recurse down paths over 255 characters and read file attributes?

Delphi : how to recurse down paths over 255 characters and read file attributes

I am writing a console app and need to traverse a directory structure with paths much greater than 255 characters and then read attributes of the files within them.

Historically, I used recursion and FindFirst using Turbo Delphi from 2006 but this seems to skip over paths greater than 255 characters.

Can I swap out the FindFirst() function for something else? or do I have to take a different approach?

like image 940
Tal Avatar asked Jun 03 '13 18:06

Tal


1 Answers

If you prefix file names with \\?\ then you enable extended-length path parsing and so escape from the 260 character path length limit.

In order for this prefix to work you need to be calling the Unicode versions of the Win32 API functions. So if you were using a Unicode Delphi then this is all you need to do. But since you are using a pre-Unicode Delphi you'll have to roll your own version of FindFirst that calls Unicode versions of the API functions. You'll be calling FindFirstFileW, FindNextFileW, FindClose and using the Unicode version of the struct, WIN32_FIND_DATAW.

These issues are discussed in great length over on MSDN: Naming Files, Paths, and Namespaces.

In your particular scenario, the documentation for FindFirstFileW calls the issue out like this:

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\?\" to the path.

Note that the two file name fields in WIN32_FIND_DATAW are limited in length to 260 characters. That is fine because they only contain the relative part of the name, that is the object name relative to the containing directory. You only need to use the \\?\ prefix when you call FindFirstFileW.

In order to use the Unicode version of this API you'll use a WideString for the lpFileName parameter of FindFirstFileW and pass it using PWideChar(FileName).

var
  FileName: WideString;
....
// initialise FileName, this will happen in your recursion
FindHandle := FindFirstFileW(PWideChar(FileName), FindData);

As for the file attributes, they can be read out of the WIN32_FIND_DATAW struct on each iteration. That part of your code need not change. The only thing you need to fix is to get the >260 char parsing on the initial call to FindFirstFileW. Everything else flows on quite normally.

like image 101
David Heffernan Avatar answered Sep 23 '22 01:09

David Heffernan