Reputation: 11
I have just installed Delphi Community Edition and thought as a newbie I was doing well until I hit the FindFirst()
procedure.
What I have is a directory list:
c:\BFUtils\01Utils
\02Utils
\03Utils
\04Utils
Then, to try out FindFirst()
to get the subdirectories of BFUtils
, I wrote the following code, which I feel is needed to simply count the number of subdirectories:
sStartPath := 'c:\BFUtils';
Result := 0;
res := FindFirst(sStartPath, faDirectory, SearchRec);
if res = 0 then begin
try
while res = 0 do begin
if SearchRec.FindData.dwFileAttributes and faDirectory <> 0 then begin
Name := SearchRec.FindData.cFileName;
if (Name <> '.') and (Name <> '..') then begin
inc(Result);
end;
end;
res := FindNext(SearchRec);
end;
finally
FindClose(SearchRec);
end;
end;
This, as it is, compiles and runs, but it only finds the BFUtils
directory.
Searching the Internet, I feel that the file mask (sStartPath
) is not correct. So I have tried:
sStartPath + '\'
sStartPath + '\*'
sStartPath + '\*.'
sStartPath + '\*.*
All these options will compile and link without errors, but when the program runs it displays an error:
"'.'" is an Invalid Item.
What else can I try here?
Upvotes: 1
Views: 967
Reputation: 596407
You are asking FindFirst()
to locate your c:\BFUtils
folder itself. To enumerate the contents of that folder, you need to use a wildcard mask instead:
function CountSubDirs(const Path: string): Integer;
var
sMask: string;
SearchRec: TSearchRec;
res: Integer;
begin
Result := 0;
sMask := IncludeTrailingPathDelimiter(Path) + '*'; // or '*.*'
res := FindFirst(sMask, faDirectory, SearchRec);
if res <> 0 then
begin
if res <> ERROR_FILE_NOT_FOUND then
RaiseLastOSError(res);
end else
begin
try
repeat
if (SearchRec.FindData.dwFileAttributes and faDirectory) = faDirectory then
begin
if (StrComp(SearchRec.FindData.cFileName, '.') <> 0) and
(StrComp(SearchRec.FindData.cFileName, '..') <> 0) then
begin
Inc(Result);
end;
end;
res := FindNext(SearchRec);
until res <> 0;
if res <> ERROR_NO_MORE_FILES then
RaiseLastOSError(res);
finally
FindClose(SearchRec);
end;
end;
end;
var NumSubDirs: Integer;
NumSubDirs := CountSubDirs('c:\BFUtils');
That has always worked fine for me. If it is not working for you, then something else is wrong with code you have not shown yet, as there is nothing in the code actually shown that can cause the "'.'" is an Invalid Item
error message you claim.
Upvotes: 1
Reputation: 2007
In modnern Delphi versions you don't necessarily need to work with FindFirst
, FindNext
and FindClose
directly anymore!
Add the unit System.IOUtils
to a uses section in your unit.
There is, among some others, the record TDirectory
:
Contains a large number of static utility methods used in directory manipulations.
TDirectory is a record containing only static methods used to perform various operations on directories. You should not declare variables of type TDirectory, since TDirectory has no instance methods or fields. Possible operations that can be completed using TDirectory include:
- Creating, renaming, and deleting directories.
- Traversing directories (also recursively).
- Manipulating directory attributes and timestamps.
For finding all subdirectories you can then use one of the overloaded GetDirectories
methods:
Use GetDirectories to obtain a list of subdirectories in a given directory. The return value of GetDirectories is a dynamic array of strings in which each element stores the name of a subdirectory.
There are three forms of the GetDirectories method:
- The first form only accepts the path of the directory for which subdirectories are enumerated.
- The second form includes a search pattern used when matching subdirectory names.
- The third form includes an option specifying whether a recursive mode will be used while enumerating.
So for counting all subdirectories you can simply do the following:
function SubDirCount(const Path: string): integer;
begin
result := Length(TDirectory.GetDirectories(Path));
end;
// somewhere else
ShowMessage(SubDirCount('C:\BFUtils').ToString);
And for your original code use this as a FileMask: sStartPath + '\.*'
Upvotes: 2