Recent

Author Topic: Find Directories in path and put in TStringList  (Read 4231 times)

nugax

  • Full Member
  • ***
  • Posts: 232
Find Directories in path and put in TStringList
« on: February 26, 2022, 02:48:56 am »
I am trying to find all directories in a path and put them in a TString list. I have the below code but it is giving me an access violation.


Code: Pascal  [Select][+][-]
  1. /Get Directories As TStringList
  2. function GetDirs(sPath: string): TStringList;
  3. var
  4.   Info: TSearchRec;
  5.   Count: longint;
  6.   TReturnString: TStringList;
  7.  
  8. begin
  9.   Count := 0;
  10.  
  11.   TReturnString := TStringList.Create;
  12.   if FindFirst(sPath + '/*', faAnyFile, Info) = 0 then
  13.   begin
  14.  
  15.     repeat
  16.       //Inc(Count);
  17.       with Info do
  18.       begin
  19.         if (Attr and faDirectory) = faDirectory then
  20.           TReturnString.Add(info.Name);
  21.         //Writeln(Name: 40, Size: 15);
  22.       end;
  23.     until FindNext(info) <> 0;
  24.     FindClose(Info);
  25.   end;
  26.  
  27. end;    
-Nugax

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Find Directories in path and put in TStringList
« Reply #1 on: February 26, 2022, 04:13:16 am »
Use Result instead of TReturnString

nugax

  • Full Member
  • ***
  • Posts: 232
Re: Find Directories in path and put in TStringList
« Reply #2 on: February 26, 2022, 05:30:03 am »
I dont understand where to use result. You mean create a TStringList locally and return in with result := MyTStringList; ?
-Nugax

Jorg3000

  • Jr. Member
  • **
  • Posts: 84
Re: Find Directories in path and put in TStringList
« Reply #3 on: February 26, 2022, 06:16:46 am »
This is my procedure to this subject ...
Here the StringList must be created outside the function by the caller. This has the advantage that it is clear to the caller that he must take care of the StringList (create and destroy).

Code: Pascal  [Select][+][-]
  1. function readSubFolderNames(const aPath: String; sl: TStringList): Integer;  // Result = -1 or Number of folders found
  2. var
  3.     sr: TSearchRec;
  4.     Mask: String;
  5. begin
  6.   if (aPath='') or (sl=nil) then Exit(-1);
  7.   if not DirectoryExists(aPath) then Exit(-1);
  8.  
  9.   Result:=0;  // Number of folders found
  10.   Mask:=IncludeTrailingPathDelimiter(aPath)+'*.*';
  11.  
  12.   initialize(sr); FillChar(sr,SizeOf(sr),0);
  13.  
  14.   if SysUtils.FindFirst(Mask,faDirectory,sr)=0 then
  15.    Repeat
  16.      if sr.Attr AND faDirectory=0 then Continue;
  17.      if (sr.Name='') or (sr.Name='.') or (sr.Name='..') then Continue;
  18.      inc(Result);
  19.      sl.Add(sr.Name);
  20.    Until SysUtils.FindNext(sr)<>0;
  21.  
  22.   SysUtils.FindClose(sr);
  23. end;
  24.  
« Last Edit: February 26, 2022, 07:34:07 am by Jorg3000 »

nugax

  • Full Member
  • ***
  • Posts: 232
Re: Find Directories in path and put in TStringList
« Reply #4 on: February 26, 2022, 07:00:06 am »
Nice code! Ill try it out.
-Nugax

nugax

  • Full Member
  • ***
  • Posts: 232
Re: Find Directories in path and put in TStringList
« Reply #5 on: February 26, 2022, 07:17:10 am »
Below is my code. I used your code exactly. I am getting index 0 out of bounds...  I confirmed the given path is correct...


Code: Pascal  [Select][+][-]
  1. //Start MRC Multiplexer
  2. class function mrcMultiPlexer.StartMRC() : string;
  3. var
  4.   sInput: string;
  5.   sOutput: string;
  6.   boolRun: integer;
  7.   sPId: integer;
  8.   sData: string;
  9.   F: textfile;
  10.   sFileName : string;
  11.   TDirList : TStringList;
  12.   iNumbdir : integer;
  13.  
  14. begin
  15.   CyberMRCMultiPlexer := TIdTCPClient.Create;
  16.   CyberMRCMultiPlexer := IdTCPClient.TIdTCPClient.Create;
  17.   CyberMRCMultiPlexer.Port := programinfo.cbbsServicesIni.Mrc_Port.ToInteger;
  18.   CyberMRCMultiPlexer.Host := programinfo.cbbsServicesIni.Mrc_Server_Hostname;
  19.   CyberMRCMultiPlexer.Connect;
  20.  
  21.   boolRun := 1;
  22.  
  23.   sOutput := self.SendHandshake();
  24.   if (sOutPut = 'SERVER~~~~~~HELLO~') then
  25.   begin
  26.     logging.WriteCBBSLog('MRC: Handshake complete with server');
  27.  
  28.     sPId := baseunix.FpFork;
  29.     if (sPID > 0) then
  30.     begin
  31.       logging.WriteCBBSLog('MRC: Connected to server');
  32.       exit(sPId.ToString);
  33.     end;
  34.  
  35.     repeat
  36.       sData := CyberMRCMultiPlexer.IOHandler.ReadLn();
  37.       if (sData = 'SERVER~~~CLIENT~~~ping~') then
  38.       begin
  39.         self.SendMsg('CLIENT~' + programinfo.cbbsMRC.sBBSName + '~~SERVER~ALL~~IMALIVE:' + programinfo.cbbsMRC.sBBSName + ' ~');
  40.       end;
  41.  
  42.  
  43.  
  44.       //Check For Ping And Reply
  45.       if (sData <> '') Then
  46.       begin
  47.        // write(sData + ' ');
  48.               end;
  49.  
  50.       if (sData <> '') Then
  51.       begin
  52.       sFileName := 'mess-' + random(99999).tostring + '.mrc';
  53.       TDirList := TStringList.Create;
  54.       //Load Directory List
  55.       iNumbdir:=cyberio.readSubFolderNames(programinfo.cbbsInfo.sSessionsDir, TDirList);
  56.  
  57.  
  58.       write('dir: ' + TDirList.Strings[0]);
  59.  
  60.  
  61.       end;
  62.       sData := '';
  63.     until (boolRun = 0);
  64.  
  65.   end;
  66.  
  67. end;
  68.  
  69.                
[



quote author=Jorg3000 link=topic=58473.msg435458#msg435458 date=1645852606]
This is my procedure to this subject ...
Here the StringList must be created outside the function by the caller. This has the advantage that it is clear to the caller that he must take care of the StringList (create and destroy).

Code: Pascal  [Select][+][-]
  1. function readSubFolderNames(const aPath: String; sl: TStringList): Integer;  // Result = -1 or Number of folders found
  2. var
  3.     sr: TSearchRec;
  4.     Mask: String;
  5. begin
  6.   if (aPath='') or (sl=nil) then Exit(-1);
  7.   if not DirectoryExists(aPath) then Exit(-1);
  8.  
  9.   Result:=0;  // Number of folders found
  10.   Mask:=IncludeTrailingPathDelimiter(aPath)+'*.*';
  11.  
  12.   initialize(sr); FillChar(sr,SizeOf(sr),0);
  13.  
  14.   if SysUtils.FindFirst(Mask,faDirectory,sr)=0 then
  15.    Repeat
  16.      if (sr.Name='.') or (sr.Name='..') then Continue;
  17.      inc(Result);
  18.      sl.Add(sr.Name);
  19.    Until SysUtils.FindNext(sr)<>0;
  20.  
  21.   SysUtils.FindClose(sr);
  22. end;
  23.  
[/quote]
-Nugax

Jorg3000

  • Jr. Member
  • **
  • Posts: 84
Re: Find Directories in path and put in TStringList
« Reply #6 on: February 26, 2022, 07:36:35 am »
Sorry, I forgot this line
Code: Pascal  [Select][+][-]
  1. if sr.Attr AND faDirectory=0 then Continue;

Updated my example above.
It's working at my computer (Windows).

dbannon

  • Hero Member
  • *****
  • Posts: 3826
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Find Directories in path and put in TStringList
« Reply #7 on: February 26, 2022, 07:37:21 am »
Might be worth noting the help text for FindFirst, put cursor on the FindFirst statement and press F1.

It warns you against assuming that setting attr to (eg) faDirectory will get only directories back. You get back ordinary files AND, in this case directories.

So, Jorg3000 code might need to look a bit like this (untested) -
Code: Pascal  [Select][+][-]
  1.     ...
  2.     if FindFirst(AppendPathDelim(APath) + '*',faDirectory, SR) = 0 then begin
  3.         try
  4.             repeat
  5.                 if ((SR.Attr and faDirectory) = faDirectory) and (ST>Name <> '.') and (SR.Name <> '..') then
  6.                          SL.Add(SR.Name);    
  7.             until FindNext(Info) <> 0;
  8.         finally
  9.             FindClose(Info);
  10.         end;
  11.     end;


The TSearchRecord does not need to be initialized or filled in, that happens in FindFirst.

On the other hand, creating the the stringlist up in the calling function as shown is really good. Creating in a function and then passing it back up stream is very bad practice that will, sooner or later lead to a memory leak.

edit:typo

Davo


« Last Edit: February 26, 2022, 07:39:30 am by dbannon »
Lazarus 4, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Jorg3000

  • Jr. Member
  • **
  • Posts: 84
Re: Find Directories in path and put in TStringList
« Reply #8 on: February 26, 2022, 07:40:45 am »
nugax, in your code you have to check if there is a String at Index 0

Code: Pascal  [Select][+][-]
  1. iNumbdir:=cyberio.readSubFolderNames(programinfo.cbbsInfo.sSessionsDir, TDirList);
  2.  
  3. if iNumbdir>0 then write('dir: ' + TDirList.Strings[0]);
  4.  

Jorg3000

  • Jr. Member
  • **
  • Posts: 84
Re: Find Directories in path and put in TStringList
« Reply #9 on: February 26, 2022, 07:46:05 am »

dbannon, the Try ... Finally in your code is a good idea!

But especially the functions FindFirst and FindNext do not contain any Exception generation.
Nevertheless, Try ... Finally ist good and right of course!  :)
« Last Edit: February 26, 2022, 07:50:57 am by Jorg3000 »

loaded

  • Hero Member
  • *****
  • Posts: 879
Re: Find Directories in path and put in TStringList
« Reply #10 on: February 26, 2022, 07:47:08 am »
Let's give an example that shows the folder browsing in tree view.
The more memory computers have, the less memory people seem to use. 😅

bytebites

  • Hero Member
  • *****
  • Posts: 789
Re: Find Directories in path and put in TStringList
« Reply #11 on: February 26, 2022, 07:58:59 am »
Code: Pascal  [Select][+][-]
  1. write('dir: ' + TDirList.Strings[0]);

Coding style issue: Don't prefix variable name with T-letter.


nugax

  • Full Member
  • ***
  • Posts: 232
Re: Find Directories in path and put in TStringList
« Reply #12 on: February 26, 2022, 07:59:48 am »
I added your code but it still isnt finding anything. Im on linux.

nugax, in your code you have to check if there is a String at Index 0

Code: Pascal  [Select][+][-]
  1. iNumbdir:=cyberio.readSubFolderNames(programinfo.cbbsInfo.sSessionsDir, TDirList);
  2.  
  3. if iNumbdir>0 then write('dir: ' + TDirList.Strings[0]);
  4.  
-Nugax

Jorg3000

  • Jr. Member
  • **
  • Posts: 84
Re: Find Directories in path and put in TStringList
« Reply #13 on: February 26, 2022, 08:39:05 am »
Is sSessionsDir definied and does that folder exist?

Code: Pascal  [Select][+][-]
  1. write(programinfo.cbbsInfo.sSessionsDir);
  2. write(IntToStr(iNumbdir));
  3.  

jamie

  • Hero Member
  • *****
  • Posts: 7774
Re: Find Directories in path and put in TStringList
« Reply #14 on: February 26, 2022, 03:26:45 pm »
The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018