<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Recursiveness &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/recursiveness/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Mon, 04 May 2026 15:32:06 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Build a Recursive Find in Files Function</title>
		<link>https://blog.xojo.com/2026/05/04/build-a-recursive-find-in-files-function/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Mon, 04 May 2026 15:32:02 +0000</pubDate>
				<category><![CDATA[Cross-Platform]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Files]]></category>
		<category><![CDATA[Method Overload]]></category>
		<category><![CDATA[Recursiveness]]></category>
		<category><![CDATA[Search]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=16179</guid>

					<description><![CDATA[In the&#160;previous post, we built a utility to find text inside files within a single folder. Today we&#8217;re upgrading that utility to support recursive searching&#8230;]]></description>
										<content:encoded><![CDATA[
<p>In the&nbsp;<a href="https://blog.xojo.com/2026/04/02/build-a-simple-find-in-files-function/">previous post</a>, we built a utility to find text inside files within a single folder. Today we&#8217;re upgrading that utility to support recursive searching with depth control. We&#8217;ll also refactor the code to keep it maintainable as it gets more complex.</p>



<h2 class="wp-block-heading" id="the-goal">The Goal</h2>



<p>We want to:</p>



<ol class="wp-block-list">
<li>Search through subfolders automatically.</li>



<li>Add a&nbsp;<code>maxDepth</code>&nbsp;parameter so we don&#8217;t accidentally crawl the entire hard drive.</li>



<li>Keep the simple version working using method overloading.</li>
</ol>



<h2 class="wp-block-heading" id="step-1-move-file-reading-to-its-own-method">Step 1: Move File Reading to its own Method</h2>



<p>The original&nbsp;<code>FindInFiles</code>&nbsp;function did everything: validated the folder, looped through children, read file content, and matched text. Adding recursion to that would make the code look ugly, so let&#8217;s refactor our code.</p>



<p>We&#8217;ll start by moving the file-reading logic into its own private method:&nbsp;<code>SearchFile</code>. This keeps the &#8220;search&#8221; logic separate from the &#8220;looping&#8221; logic.</p>



<pre class="wp-block-code"><code>Private Sub SearchFile(file As FolderItem, searchTerm As String, hits() As SearchHit)
  Try
    Var input As TextInputStream = TextInputStream.Open(file)
    input.Encoding = Encodings.UTF8
    Var lineNumber As Integer = 0
    While Not input.EndOfFile
      Var line As String = input.ReadLine
      lineNumber = lineNumber + 1
      If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
        hits.Add(New SearchHit(file.NativePath, lineNumber, line))
      End If
    Wend
    input.Close
  Catch error As IOException
    // Skip unreadable files
  End Try
End Sub</code></pre>



<h2 class="wp-block-heading" id="step-2-recursive-folder-traversal">Step 2: Recursive Folder Traversal</h2>



<p>Now we create&nbsp;<code>SearchFolder</code>. This method loops through a folder. If it finds a file, it calls&nbsp;<code>SearchFile</code>. If it finds a folder, it calls itself.</p>



<p>To keep this safe, we Use&nbsp;<code>maxDepth</code>:</p>



<ul class="wp-block-list">
<li><code>maxDepth = 0</code>: Search only this folder.</li>



<li><code>maxDepth &gt; 0</code>: Search this folder and N levels of subfolders.</li>



<li><code>maxDepth = -1</code>: Search everything (unlimited).</li>
</ul>



<pre class="wp-block-code"><code>Private Sub SearchFolder(folder As FolderItem, searchTerm As String, hits() As SearchHit, maxDepth As Integer)
   Try
    For Each item As FolderItem In folder.Children
      If item Is Nil Or Not item.Exists Or Not item.IsReadable Then Continue
      If item.IsFolder Then
        If maxDepth &lt;&gt; 0 Then
          Var nextDepth As Integer = If(maxDepth &gt; 0, maxDepth - 1, maxDepth)
          SearchFolder(item, searchTerm, hits, nextDepth)
        End If
      Else
        SearchFile(item, searchTerm, hits)
      End If
    Next
  Catch error As IOException
    // Skip inaccessible folders
  End Try
End Sub</code></pre>



<p>The logic in&nbsp;<code>nextDepth</code>&nbsp;lets us count down if there&#8217;s a limit, or stay at -1 if there isn&#8217;t.</p>



<h2 class="wp-block-heading" id="step-3-support-both-versions-with-method-overloading">Step 3: Support Both Versions with Method Overloading</h2>



<p>Overloading is a feature that lets you have multiple methods with the same name, as long as they have different parameters. In our case, it allows us to provide a simple version for one folder, and a recursive version with a depth limit. Xojo will automatically pick the right one based on the arguments you pass. You can read more about it in the&nbsp;<a href="https://documentation.xojo.com/getting_started/object-oriented_programming/oop_design_concepts.html#getting-started-object-oriented-programming-oop-design-concepts-overloading" target="_blank" rel="noreferrer noopener">Xojo Documentation</a>.</p>



<p>The default version (depth 0):</p>



<pre class="wp-block-code"><code>Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String) As SearchHit()
  Return FindInFiles(targetFolder, searchTerm, 0)
End Function</code></pre>



<p>The recursive version:</p>



<pre class="wp-block-code"><code>Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String, maxDepth As Integer) As SearchHit()
  Var hits() As SearchHit
  If targetFolder Is Nil Or Not targetFolder.Exists Or Not targetFolder.IsFolder Or searchTerm.IsEmpty Then
    Return hits
  End If
  Try
    SearchFolder(targetFolder, searchTerm, hits, maxDepth)
  Catch error As IOException
    // Skip inaccessible folders
  End Try
  Return hits
End Function</code></pre>



<p id="why-this-structure">By separating the validation, traversal, and processing, the code is much easier to modify. If you want to add Regex support, you only change&nbsp;<code>SearchFile</code>. If you want to filter by file extension, you only change&nbsp;<code>SearchFolder</code>.</p>



<h2 class="wp-block-heading" id="summary">Summary</h2>



<p>Now, you can search a single folder just like before, or crawl a directory tree with one extra parameter:</p>



<pre class="wp-block-code"><code>// Search up to 3 levels deep
Var results() As SearchUtils.SearchHit = SearchUtils.FindInFiles(myFolder, "TODO", 3)</code></pre>



<h2 class="wp-block-heading" id="the-complete-recursive-code">The Complete Recursive Code</h2>



<h3 class="wp-block-heading" id="the-searchutils-module">The SearchUtils Module</h3>



<pre class="wp-block-code"><code>Module SearchUtils

  Class SearchHit
    Public Property FilePath As String
    Public Property LineNumber As Integer
    Public Property LineText As String

    Public Sub Constructor(filePath As String, lineNumber As Integer, lineText As String)
      Self.FilePath = filePath
      Self.LineNumber = lineNumber
      Self.LineText = lineText
    End Sub
  End Class

  Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String) As SearchHit()
    // Simple usage: depth = 0
    Return FindInFiles(targetFolder, searchTerm, 0)
  End Function

  Public Function FindInFiles(targetFolder As FolderItem, searchTerm As String, maxDepth As Integer) As SearchHit()
    // Recursive usage: maxDepth ( -1 is unlimited )

    Var hits() As SearchHit

    If targetFolder Is Nil Or Not targetFolder.Exists Or Not targetFolder.IsFolder Or searchTerm.IsEmpty Then
      Return hits
    End If

    Try
      SearchFolder(targetFolder, searchTerm, hits, maxDepth)
    Catch error As IOException
      // Skip inaccessible folders
    End Try

    Return hits
  End Function

  Private Sub SearchFolder(folder As FolderItem, searchTerm As String, hits() As SearchHit, maxDepth As Integer)
    Try
      For Each item As FolderItem In folder.Children
        If item Is Nil Or Not item.Exists Or Not item.IsReadable Then Continue

        If item.IsFolder Then
          If maxDepth &lt;&gt; 0 Then
            Var nextDepth As Integer = If(maxDepth &gt; 0, maxDepth - 1, maxDepth)
            SearchFolder(item, searchTerm, hits, nextDepth)
          End If
        Else
          SearchFile(item, searchTerm, hits)
        End If
      Next
    Catch error As IOException
      // Skip inaccessible folders
    End Try
  End Sub

  Private Sub SearchFile(file As FolderItem, searchTerm As String, hits() As SearchHit)
    Try
      Var input As TextInputStream = TextInputStream.Open(file)
      input.Encoding = Encodings.UTF8
      Var lineNumber As Integer = 0

      While Not input.EndOfFile
        Var line As String = input.ReadLine
        lineNumber = lineNumber + 1

        If line.Contains(searchTerm, ComparisonOptions.CaseInsensitive) Then
          hits.Add(New SearchHit(file.NativePath, lineNumber, line))
        End If
      Wend

      input.Close
    Catch error As IOException
      // Skip unreadable files
    End Try
  End Sub
End Module</code></pre>



<p>Happy coding!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Recursion: Emptying a Folder</title>
		<link>https://blog.xojo.com/2019/02/04/recursion-emptying-a-folder/</link>
		
		<dc:creator><![CDATA[Javier Menendez]]></dc:creator>
		<pubDate>Mon, 04 Feb 2019 10:00:38 +0000</pubDate>
				<category><![CDATA[Learning]]></category>
		<category><![CDATA[AprendeXojo]]></category>
		<category><![CDATA[FolderItem]]></category>
		<category><![CDATA[Recursiveness]]></category>
		<category><![CDATA[Xojo Programming Language]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=5363</guid>

					<description><![CDATA[Do you need code to delete the files and folders from the selected folder? In that case, there is a technique I propose to you and that is based on the recursivity. That is, the hability of a function to calling itself until the task is complete; in this case, the function will call itself every time it detects a new folder/directory inside the designated original folder/directory.]]></description>
										<content:encoded><![CDATA[<p>Do you need code to delete the files and folders from the selected folder? In that case, there is a technique I propose to you and that is based on <strong>recursion</strong>. That is, the ability of a function to call itself repeatedly until the task is complete; in this case, the function will call itself every time it detects a new folder/directory inside the designated original folder/directory.<span id="more-5363"></span></p>
<p>But, beware! The following implementation will delete all the files and original containing folder every time it finds an alias… not just the alias. Anyway, it is easy to change this behavior in case you just want to delete the alias and not the original it points to.</p>
<p>As you probably already know, when we work with files or folders in Xojo we are actually using the <a href="http://documentation.xojo.com/api/files/folderitem.html">FolderItem</a> class, so we are able to access to all its properties and the methods acting on every instance: changing the file/folder/directory name, getting the creation date, create a copy, to move the file and/or folder to a new destination … and also for deleting the file or folder.</p>
<p>In addition, <b>recursion</b> is a technique that is not always appropriate because the function adds a new frame of data to the execution stack every time it calls itself, something that can cause a stack overflow error if it calls itself a large amount amount of times. This may occur, for example, if a folder or directory has many nested folders. To alleviate this, we can resort to the mechanism provided by the Xojo language itself and gracefully catch this situation on runtime.</p>
<p>Having said this, what is the best way to implement our recursive function so it is available to all the FolderItem instances? You may create a new FolderItem subclass, but that would mean that the method would only be available from the instances created from the subclass, and not for those created from the parent FolderItem class. The answer in this case is to apply it as a <a href="http://documentation.xojo.com/api/language/extends.html"><strong>Class Extension</strong></a> technique. This technique allows us to add additional functionality to a existing class without needing to subclass it previously.</p>
<p>The way to add a Class Extension in Xojo is through a <a href="http://documentation.xojo.com/api/language/module.html"><b>Module</b></a>, so it gives us the option to set the method as globally available from all the app code. This way, the Xojo compiler will know that we want to extend a particular class because we use the <code>Extends</code> keyword in the method definition, followed by the variable whose data type designates the class we want to extend.</p>
<p>So, our method (or function) signature will be:</p>
<p><code>DeleteAllFilesInside(extends f as FolderItem)</code></p>
<p>Once we&#8217;ve added that method to a Module it&#8217;s important to set the <code>Scope</code> to the value <code>Global</code> in the Inspector. Now we can put the following code inside the associated Code Editor for the method, so this is the responsible of deleting the files and call itself every time it detects a new folder/directory:</p>
<pre>  // We keep the initial (designated) FolderItem
  // So it doesn't get deleted.

  Static originFolder As String = f.NativePath

  // Is the pointed FolderItem a Directory?
  // then proceed to iterate the containing
  // files and (probably) folders.

  If f.Directory Then

    For n As Integer = f.Count DownTo 1

      If f.Item(n) &lt;&gt; Nil Then

        // Are we detecting a new folder
        // while iterating the current one?
        // then we call the function again!

        If f.item(n).Directory And f.Count &lt;&gt; 0 Then

          Dim f1 As FolderItem = f.item(n)

          f1.deleteAllFilesInside

        End If

        // Otherwhise, we proceed to delete the file/folder
        // always it is not the initial FolderItem
        // that is, the initial folder/directory

        If f.item(n) &lt;&gt; Nil And f.item(n).NativePath &lt;&gt; originfolder Then f.item(n).Delete

      End If
      
    Next
  End
  
  // we are outside a folder, so let's check
  // that the pointing FolderItem is not the initial one
  // if it doens't, then we can delete the file/folder

  If f &lt;&gt; Nil And f.NativePath &lt;&gt; originFolder Then f.Delete

</pre>
<p><em>Javier Rodri­guez has been the Xojo Spanish Evangelist since 2008, he’s also a Developer, Consultant and Trainer who has be using Xojo since 1998. He manages <a href="http://www.aprendexojo.com">AprendeXojo.com</a> and is the developer behind the GuancheMOS plug-in for Xojo Developers, Markdown Parser for Xojo, HTMLColorizer for Xojo and the Snippery app, among others.</em></p>
<p>*Watch a <a href="https://www.youtube.com/watch?v=1TNxnYs91xY">video of this Tutorial in Spanish</a></p>
<p>*<a href="https://www.aprendexojo.com/2019/01/recursividad-vaciar-contenido-de-una-carpeta/">Read this post in Spanish</a></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
