{"id":447,"date":"2009-08-11T22:39:58","date_gmt":"2009-08-11T12:39:58","guid":{"rendered":"http:\/\/www.malcolmgroves.com\/blog\/?p=447"},"modified":"2015-03-04T13:55:18","modified_gmt":"2015-03-04T02:55:18","slug":"ioutilspas-oo-file-system-access-in-delphi-2010","status":"publish","type":"post","link":"http:\/\/www.malcolmgroves.com\/blog\/?p=447","title":{"rendered":"IOUtils.pas &ndash; OO File System Access in Delphi 2010"},"content":{"rendered":"<p>Delphi has long had various functions to let you work with the file system, but one of the new features of Delphi 2010 are some nice wrappers for working with files, paths and directories.<\/p>\n<p>IOUtils.pas is the file in question, and it\u2019s definitely worth a look. Each time I\u2019ve had a look in there during the Field Test I\u2019ve found more interesting stuff to play with. While I\u2019m still exploring it, I thought I\u2019d post a few examples to show you the kind of things you can get up to.<\/p>\n<p>Firstly, something easy:<\/p>\n<pre lang=\"Delphi\">procedure TForm2.Button2Click(Sender: TObject);  \r\nvar   \r\n  Path : string; \r\nbegin \r\n  if not TDirectory.Exists(edtPath.Text) then \r\n    Caption := 'Invalid Path' \r\n  else \r\n    Caption := edtPath.Text;\r\n \r\n  ListBox1.Clear;\r\n\r\n  for Path in TDirectory.GetFiles(edtPath.Text, edtFilter.Text) do \r\n    Listbox1.Items.Add(Format('Name = %s', [Path])); \r\nend;<\/pre>\n<p>First we check if the path provided in the edtPath edit box exists. Assuming it does, we then use a for..in statement to get back each file in that directory that matches the filter passed in as the second parameter.<\/p>\n<p>If you look a little further in IOUtils.pas, you\u2019ll see TDirectory has a type declared in it called a TFilterPredicate:<\/p>\n<pre lang=\"Delphi\">TFilterPredicate = reference to function(const Path: string; const SearchRec: TSearchRec): Boolean;<\/pre>\n<p>One of the places it is used is in an overloaded version of GetFiles, like so:<\/p>\n<pre lang=\"Delphi\">procedure TForm2.Button1Click(Sender: TObject); \r\nvar \r\n  Path : string; \r\n  FilterPredicate : TDirectory.TFilterPredicate; \r\nbegin \r\n  if not TDirectory.Exists(edtPath.Text) then \r\n    Caption := 'Invalid Path' \r\n  else \r\n    Caption := edtPath.Text;\r\n\r\n  ListBox1.Clear;\r\n\r\n  FilterPredicate := function(const Path: string; const SearchRec: TSearchRec): Boolean \r\n                     begin \r\n                       Result := (TPath.MatchesPattern(SearchRec.Name, edtFilter.Text, False)) AND \r\n                                 (SearchRec.Attr = faArchive); \r\n                     end;\r\n\r\n  for Path in TDirectory.GetFiles(edtPath.Text, FilterPredicate) do \r\n    Listbox1.Items.Add(Format('Name = %s', [Path])); \r\nend;<\/pre>\n<p>We implement the TFilterPredicate anonymous method to check that each file matches a wildcard pattern and that it also has its Archive flag set. We can then pass it into our call to TDirectory.GetFiles and our code in the for..in statement will only be called for files that match our criteria.<\/p>\n<p>This is all fine for a single directory, but what if we want to walk over the full tree of directories? Easy, just alter our code to look like this:<\/p>\n<pre lang=\"Delphi\">procedure TForm2.Button3Click(Sender: TObject);\r\nvar\r\n  Path, Directory : string;\r\n  FilterPredicate : TDirectory.TFilterPredicate;\r\nbegin\r\n  if not TDirectory.Exists(edtPath.Text) then\r\n    Caption := 'Invalid Path'\r\n  else\r\n    Caption := edtPath.Text;\r\n\r\n  ListBox1.Clear;\r\n\r\n  FilterPredicate := function(const Path: string; const SearchRec: TSearchRec): Boolean\r\n                     begin\r\n                       Result := (TPath.MatchesPattern(SearchRec.Name, edtFilter.Text, False)) AND \r\n                                 (SearchRec.Attr = faArchive);\r\n                     end;\r\n\r\n  for Directory in TDirectory.GetDirectories(edtPath.Text, TSearchOption.soAllDirectories, nil) do\r\n    for Path in TDirectory.GetFiles(Directory, FilterPredicate) do\r\n      Listbox1.Items.Add(Format('Name = %s', [Path]));\r\nend;<\/pre>\n<p>We add another for..in statement before the existing one. This one for each Directory in TDirectory.GetDirectories. The second parameter indicates whether we only want to get the top level directories in the path we specify, or whether we want to do all directories , all the way down. In this case I\u2019m specifying the latter. The Third parameter is actually another TDirectory.TFilterPredicate, so we could do further filtering of the directories that match, however I\u2019m passing in nil so all directories will match. Just keep your wits about you while testing, and don\u2019t test it with c:\\ as I did<\/p>\n<p>One thing to note, TDirectory.GetDirectories returns child directories of the path we\u2019ve specified (and their child directories, etc if you\u2019ve specified TSearchOption.soAllDirectories), but obviously not the path we pass in itself. That probably sounds obvious, but in this example we\u2019ve subtly altered the behaviour a little, because the files in the directory we specify are not checked anymore. Now you\u2019re aware of this, I\u2019m sure you can figure out how to deal.<\/p>\n<p>There\u2019s a whole bunch more that can be done, such as encrypt files, move directories, etc. IOUtils looks to be a really powerful unit, and is well worth a little playing to get familiar with it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Delphi has long had various functions to let you work with the file system, but one of the new features of Delphi 2010 are some nice wrappers for working with files, paths and directories. IOUtils.pas is the file in question, and it\u2019s definitely worth a look. Each time I\u2019ve had a look in there during [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[19,48],"class_list":["post-447","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-delphi","tag-embarcadero"],"_links":{"self":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/447","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=447"}],"version-history":[{"count":9,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/447\/revisions"}],"predecessor-version":[{"id":1758,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/447\/revisions\/1758"}],"wp:attachment":[{"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=447"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=447"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.malcolmgroves.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=447"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}