I have a file with a fixed pattern (CONST_) and a running number (XXXX) like this: CONST_XXXX.XYZ
.
I am looking for an efficient way to get the file with the highest number in Delphi. Traversing with FindFirst
/ FindNext
seems to be inefficient, if there are many files.
It is well known that finding the maximum of a list, in general, requires all items to be checked. And I believe that the most efficient way to do that is to use FindFirstFile/FindNextFile
or related APIs. It's hard to imagine that there will be any real way to improve on the official system API for enumerating files.
That was certainly the opinion offered here: Is there a faster alternative to enumerating folders than FindFirstFile/FindNextFile with C++? Note that I am rejecting out of hand the option of parsing the file system by hand. I don't regard that as being very practical.
On the other hand, this answer offers hope that FindFirstFileEx
with FindExInfoBasic
and FIND_FIRST_EX_LARGE_FETCH
may lead to better performance than plain old FindFirstFile
.
You may need to look for an alternative solution to your problem, one that does not involve repeated enumerations of a directory full of files. Perhaps using a database so that you can take advantage of indexing. In fact, it is plausible that the built-in indexing service could be of use.
How about something like this:
for I := 0 to MAX_DIGITS - 4
begin
S := 'CONST_' + StringOfChar('0', I);
for C := '9' downto '1' do
begin
if FindFirst(S + C + '*.XYZ', faAnyFile, SearchResult) = 0 then
begin
//Code to iterate through the results using FindNext
//and returning "biggest" Name
Result := SearchResult.FileName
while FindNext(SearchResult) = 0
//ommitted: handling dirs / hidden
if CompareStr(Result, SearchResult.FileName) < 0 then
Result := SearchResult.FileName;
//adding recursion instead of while... should make it even faster
FindClose(SearchResult);
Break;
end;
end;
end;
Warning: this code has not been tested
An alternative would be
for I := 9999 downto 0 do
begin
FileName := Format ('CONST_%.4d.XYZ', [I]);
if FileExists(FileName) then
Break;
end;
Whether this is faster or not depends on the numbers you are expecting and on the performance of FileExists
vs. FindFirst
which I cannot comment on.
The another way is to read all occurring CONST_*.XYZ
into FileListBox and then show the last.
procedure TForm1.Button1Click(Sender: TObject);
begin
FileListBox1.Directory:='D:\samples';
FileListBox1.Mask:='CONST_*.XYZ';
FileListBox1.Update;
Label1.Caption:= FileListBox1.Items[FileListBox1.Items.Count-1];
end;
To make it faster, you can use a function
function getRegion(filestr:string):Boolean;
begin
if FindFirst(filestr, faAnyFile, searchResult) = 0 then result:=true else result:=false;
if result then begin
findN:=filestr;
end;
end;
begin
SetCurrentDir('D:\samples');
for i:=9 downto 0 do begin
if getRegion(Format ('CONST_%.1d*.XYZ', [i])) then break;
end;
FileListBox1.Directory:='D:\samples';
FileListBox1.Mask:=findN;
FileListBox1.Update;
Label1.Caption:= FileListBox1.Items[FileListBox1.Items.Count-1];
Update
For test A) files were created from 0000-4999
For test B) files were created from 0000-9999
TestA made files from 0000
to only 4999
because user jpfollenius
uses downto
from 0000
to 4999
= 5000 files
from 9999
downto 4999
= 5000 files
Testtable TestA
Test B
I'm shure with more files 50000 files my solution loads 10000 filenames
for example 5 0000
to 5 9999
that takes
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.