I've been away from programming a while. While coding a simple project, I've come across TStringDynArray. The below code snippet I've entered magically works (I'm using XE4), no errors, no warnings, no hints. In the (distant) past, I recall having to set the length of a dynamic array. That's no longer needed? Am I creating some memory leak with the below code? No need to free up memory? Thanks, Bob Lincoln ================================================== procedure TForm1.btnZipFolderClick(Sender: TObject); var DirToZip: string; ZipList: TStringDynArray; I: integer; begin DirToZip := 'C:\Users\My Name\Desktop\My Folder'; ZipList := TDirectory.GetFiles(DirToZip, '*', TSearchOption.soAllDirectories); for I := 0 to Length(ZipList) do ListBox1.Items.Add(ZipList[I]); end;
![]() |
0 |
![]() |
Actually, the for loop should be: for I := 0 to Length(ZipList) - 1 do ListBox1.Items.Add(ZipList[I]); On 9/2/2013 12:08 PM, Robert Lincoln wrote: > I've been away from programming a while. While coding a simple project, > I've come across TStringDynArray. The below code snippet I've entered > magically works (I'm using XE4), no errors, no warnings, no hints. > > In the (distant) past, I recall having to set the length of a dynamic > array. That's no longer needed? Am I creating some memory leak with > the below code? No need to free up memory? > > Thanks, > > Bob Lincoln > > ================================================== > > > procedure TForm1.btnZipFolderClick(Sender: TObject); > var > DirToZip: string; > ZipList: TStringDynArray; > I: integer; > begin > > DirToZip := 'C:\Users\My Name\Desktop\My Folder'; > > ZipList := TDirectory.GetFiles(DirToZip, '*', > TSearchOption.soAllDirectories); > > for I := 0 to Length(ZipList) do > ListBox1.Items.Add(ZipList[I]); > > end; >
![]() |
0 |
![]() |
Robert wrote: > In the (distant) past, I recall having to set the length of a > dynamic array. If you are allocating the array yourself, then yes. That is not the case in your example. > Am I creating some memory leak with the below code? > No need to free up memory? No, you are not creating a memory leak. TDirectory.GetFiles() allocates and returns its own dynamic array of strings, which you are then taking ownership of. A dynamic array is reference counted. When your local ZipList variable goes out of scope, the array will be freed because its reference count falls to 0. -- Remy Lebeau (TeamB)
![]() |
0 |
![]() |
Robert Lincoln wrote: > I've been away from programming a while. While coding a simple > project, I've come across TStringDynArray. The below code snippet > I've entered magically works (I'm using XE4), no errors, no warnings, > no hints. > > In the (distant) past, I recall having to set the length of a dynamic > array. That's no longer needed? Am I creating some memory leak with > the below code? No need to free up memory? There is no magic involved here. TStringDynArray is an array of string, and the code behaves exactly as if it were declared with ZipList: array of string. The TDirectory.GetFiles function returns a dynamic array it has sized and filled with the files to return internally. And like for any other dynamic array the compiler adds code to make sure the memory for the array is released when the array variable goes out of scope. > procedure TForm1.btnZipFolderClick(Sender: TObject); > var > DirToZip: string; > ZipList: TStringDynArray; > I: integer; > begin > DirToZip := 'C:\Users\My Name\Desktop\My Folder'; > ZipList := TDirectory.GetFiles(DirToZip, '*', TSearchOption.soAllDirectories); > for I := 0 to Length(ZipList) do > ListBox1.Items.Add(ZipList[I]); -- Peter Below (TeamB)
![]() |
0 |
![]() |
Robert wrote: > Actually, the for loop should be: > > for I := 0 to Length(ZipList) - 1 do > ListBox1.Items.Add(ZipList[I]); You can alternatively use a for..in loop instead: {code:delphi} var filename: string; for filename in ZipList do ListBox1.Items.Add(filename); {code} -- Remy Lebeau (TeamB)
![]() |
0 |
![]() |
Peter wrote: > The TDirectory.GetFiles function returns a dynamic array it has sized and > filled with the files to return internally. An array that is sized quite inefficiently, I might add - it is resized/reallocated on every single file that is found. Embarcadero should know better than to do that on (potentially) large lists. I would think it would be better to add the files to a TStringList first, and then allocate+fill the final array only once from that. And then maybe they should forget the array altogether and just return the TStringList itself (or let the caller pass in a TStrings to be filled). Sometimes I worry about what Embarcadero designers are thinking when they design public interfaces with inefficient implementations. -- Remy Lebeau (TeamB)
![]() |
0 |
![]() |
Peter, | There is no magic involved here. TStringDynArray is an array of | string, and the code behaves exactly as if it were declared with | ZipList: array of string. The TDirectory.GetFiles function returns a | dynamic array it has sized and filled with the files to return | internally. Do you know if XE and later know how to handle both Unicode and ANSI strings in TStringDynArray? (I'm to busy at the moment to play with it. <g>) -- Q 09/02/2013 13:56:09 1.19.1.372 [Q'sBrokenToolBar] [Running on TQ]
![]() |
0 |
![]() |
Where can one find the code for TDirectory.GetFiles? When I look in System.IOUtils.pas, I just see a call to GetFiles(). Where does that come from? In other words, how can one know: "... it is resized/reallocated on every single file that is found." Also, thanks for everyone's responses so quickly. I obviously need to go back and relearn some things. Bob Lincoln On 9/2/2013 1:46 PM, Remy Lebeau (TeamB) wrote: > Peter wrote: > >> The TDirectory.GetFiles function returns a dynamic array it has sized and >> filled with the files to return internally. > > An array that is sized quite inefficiently, I might add - it is resized/reallocated > on every single file that is found. Embarcadero should know better than > to do that on (potentially) large lists. I would think it would be better > to add the files to a TStringList first, and then allocate+fill the final > array only once from that. And then maybe they should forget the array altogether > and just return the TStringList itself (or let the caller pass in a TStrings > to be filled). Sometimes I worry about what Embarcadero designers are thinking > when they design public interfaces with inefficient implementations. > > -- > Remy Lebeau (TeamB) >
![]() |
0 |
![]() |
Quentin wrote: > Do you know if XE and later know how to handle both Unicode > and ANSI strings in TStringDynArray? TStringDynArray only knows about the "string" data type, which is Ansi in D2007 and earlier, and Unicode in D2009 and later. You can certainly declare "array of AnsiString" in your own code, but you can't make the RTL use it. The RTL/VCL is almost exclusively Unicode nowadays (if you don't count Ansi-oriented functions that are still provided for backwards compatibility purposes). -- Remy Lebeau (TeamB)
![]() |
0 |
![]() |
Robert wrote: > Where can one find the code for TDirectory.GetFiles? System.IOUtils.pas in the $(BDS)\source\rtl\common folder. > When I look in System.IOUtils.pas, I just see a call to GetFiles(). > Where does that come from? TDirectory.GetFiles() calls TDirectory.DoGetFiles(), which calls TDirectory.WalkThroughDirectory() with a callback function that adds each matching file to the Result array, resizing the array each time. > In other words, how can one know: > > "... it is resized/reallocated on every single file that is found." By this code in TDirectory.DoGetFiles(): {code:delphi} if CanAdd then begin SetLength(ResultArray, Length(ResultArray) + 1); ResultArray[Length(ResultArray) - 1] := TPath.DoCombine(Path, FileInfo.Name, False); end; {code} -- Remy Lebeau (TeamB)
![]() |
0 |
![]() |
Remy, That's pretty much what I would have guessed. Thanks!!! -- Q 09/02/2013 15:31:13 1.19.1.372 [Q'sBrokenToolBar] [Running on TQ]
![]() |
0 |
![]() |
Remy Lebeau (TeamB) wrote: > Peter wrote: > > > The TDirectory.GetFiles function returns a dynamic array it has sized and > > filled with the files to return internally. > > An array that is sized quite inefficiently, I might add - it is resized/reallocated > on every single file that is found. Embarcadero should know better than > to do that on (potentially) large lists. I would think it would be better > to add the files to a TStringList first, and then allocate+fill the final > array only once from that. And then maybe they should forget the array altogether > and just return the TStringList itself (or let the caller pass in a TStrings > to be filled). Sometimes I worry about what Embarcadero designers are thinking > when they design public interfaces with inefficient implementations. Or they could size the return list to some UWAG (unscientific wild-ass guess) size and track the file count, bumping the list occasionally, and then set the Length when they're done. Actually, that's pretty much what the original TStringList did. -- John
![]() |
0 |
![]() |
Robert, > Actually, the for loop should be: > > for I := 0 to Length(ZipList) - 1 do > ListBox1.Items.Add(ZipList[I]); as Remy said you can also use a for-in-loop or the old Low and High functions. {code: Delphi} for I := Low(ZipList) to High(ZipList) do ListBox1.Items.Add(ZipList[I]); {code} -- Roman Kassebaum Embarcadero Technology Partner Embarcadero MVP Roman's Blog: http://blog.kassebaum.eu
![]() |
0 |
![]() |
Remy Lebeau (TeamB) wrote: > Peter wrote: > > > The TDirectory.GetFiles function returns a dynamic array it has sized and > > filled with the files to return internally. > > An array that is sized quite inefficiently, I might add - it is resized/reallocated > on every single file that is found. Embarcadero should know better than > to do that on (potentially) large lists. I would think it would be better > to add the files to a TStringList first, and then allocate+fill the final > array only once from that. And then maybe they should forget the array altogether > and just return the TStringList itself (or let the caller pass in a TStrings > to be filled). Sometimes I worry about what Embarcadero designers are thinking > when they design public interfaces with inefficient implementations. Or they could size the return list to some UWAG (unscientific wild-ass guess) size and track the file count, bumping the list occasionally, and then set the Length when they're done. Actually, that's pretty much what the original TStringList did. -- John
![]() |
0 |
![]() |
John Treder wrote: Dunno why Xananews pumped this again this morning. -- Tredmill
![]() |
0 |
![]() |
Quentin Correll wrote: > Peter, > > > There is no magic involved here. TStringDynArray is an array of > > string, and the code behaves exactly as if it were declared with > > ZipList: array of string. The TDirectory.GetFiles function returns > > a dynamic array it has sized and filled with the files to return > > internally. > > Do you know if XE and later know how to handle both Unicode and ANSI > strings in TStringDynArray? (I'm to busy at the moment to play with > it. <g>) TStringDynArray is simply an array of string, i.e. of one single type. That will handle the string type that is currently aliased to "string". Other types will be converted, if this is implicitly possible. -- Rudy Velthuis (TeamB) http://www.teamb.com "I'm all in favor of keeping dangerous weapons out of the hands of fools. Let's start with typewriters." -- Frank Lloyd Wright (1868-1959)
![]() |
0 |
![]() |
Rudy, | TStringDynArray is simply an array of string, i.e. of one single type. | That will handle the string type that is currently aliased to | "string". Other types will be converted, if this is implicitly | possible. Thanks! -- Q 09/04/2013 10:44:47 1.19.1.372 [Q'sBrokenToolBar] [Running on TQ]
![]() |
0 |
![]() |