Click here to Skip to main content
15,885,366 members
Articles / Programming Languages / C#

xmove - Regex enabled file move command

Rate me:
Please Sign up or sign in to vote.
4.81/5 (30 votes)
5 Nov 2003MIT4 min read 149.3K   2.2K   49  
Moves files or directories using regular expression patterns.
/*
 * Common.IO.FindFile - Regex enabled file/directory search class
 * Copyright (C) 2003 S�bastien Lorion
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

namespace Common.IO
{
	public class FindFile
	{
		/// <summary>
		/// Provides attributes for files and directories to look for during a search.
		/// </summary>
		[Flags]
		public enum SearchAttributes
		{
			Archive = FileAttributes.Archive,
			Compressed = FileAttributes.Compressed,
			Device = FileAttributes.Device,
			Directory = FileAttributes.Directory,
			Encrypted = FileAttributes.Encrypted,
			Hidden = FileAttributes.Hidden,
			Normal = FileAttributes.Normal,
			NotContentIndexed = FileAttributes.NotContentIndexed,
			Offline = FileAttributes.Offline,
			ReadOnly = FileAttributes.ReadOnly,
			ReparsePoint = FileAttributes.ReparsePoint,
			SparseFile = FileAttributes.SparseFile,
			System = FileAttributes.System,
			Temporary = FileAttributes.Temporary,
			All = 0x7FFF,
			AnyFile = All - Directory
		}

		/// <summary>
		/// The delegate that is called each time a file is found during a search by <see cref="Common.IO.FindFile"/>
		/// </summary>
		/// <remarks>Sets the return value to true to stop the search.</remarks>
		public delegate bool FoundAFile(String path, FileAttributes fileAttributes);

		public static Int32 Search(String basePath, String searchPattern, SearchAttributes searchAttributes, FoundAFile callback)
		{
			return Search(basePath, searchPattern, false, RegexOptions.None, searchAttributes, -1, -1, callback);
		}
		public static Int32 Search(String basePath, String searchPattern, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			return Search(basePath, searchPattern, false, RegexOptions.None, searchAttributes, maxDepth, maxResults, callback);
		}
		public static Int32 Search(String basePath, String searchPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, FoundAFile callback)
		{
			return Search(basePath, searchPattern, true, regexOptions, searchAttributes, -1, -1, callback);
		}
		public static Int32 Search(String basePath, String searchPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			return Search(basePath, searchPattern, true, regexOptions, searchAttributes, maxDepth, maxResults, callback);
		}


		/// <summary>
		/// Calls a delegate each time a file is found that match the specified search pattern.
		/// </summary>
		/// <param name="basePath">The starting point of the search.</param>
		/// <param name="searchPattern">The search string to match against the names of files in path.</param>
		/// <param name="isRegexPattern">Indicates if the search pattern is a regular expression.</param>
		/// <param name="regexOptions">The options for the regex engine.</param>
		/// <param name="searchAttributes">The attributes for files and directories to look for during the search.</param>
		/// <param name="maxDepth">The maximum level of recursion.</param>
		/// <param name="maxResults">The maximum number of results to return.</param>
		/// <param name="callback">The callback function to call each time a file is found.</param>
		/// <returns>The number of results.</returns>
		private static Int32 Search(String basePath, String searchPattern, bool isRegexPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			if (isRegexPattern)
				return Search(basePath, new String[] {searchPattern}, isRegexPattern, regexOptions, searchAttributes, maxDepth, maxResults, callback);
			else
			{
				Int32 resultCount = 0;

				if (maxDepth < 0)
					maxDepth = Int32.MaxValue;

				if (maxResults < 0)
					maxResults = Int32.MaxValue;

				Search(basePath, searchPattern, searchAttributes, maxDepth, maxResults, callback, 0, ref resultCount);

				return resultCount;
			}
		}

		public static Int32 Search(String basePath, String[] searchPattern, SearchAttributes searchAttributes, FoundAFile callback)
		{
			return Search(basePath, searchPattern, false, RegexOptions.None, searchAttributes, -1, -1, callback);
		}
		public static Int32 Search(String basePath, String[] searchPattern, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			return Search(basePath, searchPattern, false, RegexOptions.None, searchAttributes, maxDepth, maxResults, callback);
		}
		public static Int32 Search(String basePath, String[] searchPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, FoundAFile callback)
		{
			return Search(basePath, searchPattern, true, regexOptions, searchAttributes, -1, -1, callback);
		}
		public static Int32 Search(String basePath, String[] searchPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			return Search(basePath, searchPattern, true, regexOptions, searchAttributes, maxDepth, maxResults, callback);
		}

		/// <summary>
		/// Calls a delegate each time a file is found that match the specified search pattern.
		/// </summary>
		/// <param name="basePath">The starting point of the search.</param>
		/// <param name="searchPatterns">The search strings to match against the names of files in path.</param>
		/// <param name="isRegexPattern">Indicates if the search patterns are regular expressions.</param>
		/// <param name="regexOptions">The options for the regex engine.</param>
		/// <param name="searchAttributes">The attributes for files and directories to look for during the search.</param>
		/// <param name="maxDepth">The maximum level of recursion.</param>
		/// <param name="maxResults">The maximum number of results to return.</param>
		/// <param name="callback">The callback function to call each time a file is found.</param>
		/// <returns>The number of results.</returns>
		private static Int32 Search(String basePath, String[] searchPatterns, bool isRegexPattern, RegexOptions regexOptions, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback)
		{
			StringBuilder totalPattern = new StringBuilder();

			totalPattern.Append('(');
			foreach (String pattern in searchPatterns)
			{
				if (isRegexPattern)
					totalPattern.Append(pattern);
				else
				{
					String converted = pattern.Replace(".", @"\.");
					converted = converted.Replace("*", ".*");
					totalPattern.Append(converted);
				}
					
				totalPattern.Append('|');
			}

			totalPattern[totalPattern.Length - 1] = ')';

			Int32 resultCount = 0;

			if (maxDepth < 0)
				maxDepth = Int32.MaxValue;

			if (maxResults < 0)
				maxResults = Int32.MaxValue;

			regexOptions = regexOptions | RegexOptions.Compiled;
			Regex regex = new Regex(totalPattern.ToString(), regexOptions);

			SearchRegex(basePath, regex, searchAttributes, maxDepth, maxResults, callback, 0, ref resultCount);

			return resultCount;
		}

		/// <summary>
		/// Calls a delegate each time a file is found that match the specified search pattern.
		/// </summary>
		/// <param name="basePath">The starting point of the search.</param>
		/// <param name="searchPattern">The search string to match against the names of files in path.</param>
		/// <param name="searchAttributes">The attributes for files and directories to look for during the search.</param>
		/// <param name="maxDepth">The maximum level of recursion.</param>
		/// <param name="maxResults">The maximum number of results to return.</param>
		/// <param name="callback">The callback function to call each time a file is found.</param>
		/// <param name="nestedLevel">(Internal) Indicates the current level of recursion.</param>
		/// <param name="resultCount">(Internal) Indicates the number of results found so far.</param>
		private static void Search(String basePath, String searchPattern, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback, Int32 nestedLevel, ref Int32 resultCount)
		{
			try
			{
				bool isCanceled = false;

				foreach (String path in Directory.GetDirectories(basePath, searchPattern))
				{
					if (!isCanceled && resultCount < maxResults)
					{
						if ((searchAttributes & SearchAttributes.Directory) != 0)
						{
							FileAttributes fileAttributes = File.GetAttributes(path);

							if (((Int32)fileAttributes & (Int32)searchAttributes) != 0)
							{
								isCanceled = callback(path, fileAttributes);
								resultCount++;
							}
						}
					}
					else
						break;
					
					if (nestedLevel < maxDepth)
						Search(path, searchPattern, searchAttributes, maxDepth, maxResults, callback, nestedLevel + 1, ref resultCount);
				}

				// if we only need directories, we might as well skip this section altogether
				if (!isCanceled || (Int32)searchAttributes == (Int32)FileAttributes.Directory)
				{
					foreach (String path in Directory.GetFiles(basePath, searchPattern))
					{
						if (!isCanceled && resultCount < maxResults)
						{
							FileAttributes fileAttributes = File.GetAttributes(path);

							if (((Int32)fileAttributes & (Int32)searchAttributes) != 0)
							{
								isCanceled = callback(path, fileAttributes);
								resultCount++;
							}
						}
						else
							break;
					}
				}
			}
			catch (System.UnauthorizedAccessException) {}
		}

		/// <summary>
		/// Calls a delegate each time a file is found that match the specified search pattern.
		/// </summary>
		/// <param name="basePath">The starting point of the search.</param>
		/// <param name="searchPattern">The search pattern to match against the names of files in path.</param>
		/// <param name="searchAttributes">The attributes for files and directories to look for during the search.</param>
		/// <param name="maxDepth">The maximum level of recursion.</param>
		/// <param name="maxResults">The maximum number of results to return.</param>
		/// <param name="callback">The callback function to call each time a file is found.</param>
		/// <param name="nestedLevel">(Internal) Indicates the current level of recursion.</param>
		/// <param name="resultCount">(Internal) Indicates the number of results found so far.</param>
		private static void SearchRegex(String basePath, Regex searchPattern, SearchAttributes searchAttributes, Int32 maxDepth, Int32 maxResults, FoundAFile callback, Int32 nestedLevel, ref Int32 resultCount)
		{
			try
			{
				bool isCanceled = false;

				foreach (String path in Directory.GetDirectories(basePath, "*"))
				{
					if (!isCanceled && resultCount < maxResults)
					{
						if ((searchAttributes & SearchAttributes.Directory) != 0)
						{
							FileAttributes fileAttributes = File.GetAttributes(path);

							if (((Int32)fileAttributes & (Int32)searchAttributes) != 0)
							{
								if (searchPattern.IsMatch(Path.GetFileName(path)))
								{
									isCanceled = callback(path, fileAttributes);
									resultCount++;
								}
							}
						}
					}
					else
						break;
					
					if (nestedLevel < maxDepth)
						SearchRegex(path, searchPattern, searchAttributes, maxDepth, maxResults, callback, nestedLevel + 1, ref resultCount);
				}

				// if we only need directories, we might as well skip this section altogether
				if (!isCanceled || (Int32)searchAttributes == (Int32)FileAttributes.Directory)
				{
					foreach (String path in Directory.GetFiles(basePath, "*"))
					{
						if (!isCanceled && resultCount < maxResults)
						{
							FileAttributes fileAttributes = File.GetAttributes(path);

							if (((Int32)fileAttributes & (Int32)searchAttributes) != 0)
							{
								if (searchPattern.IsMatch(Path.GetFileName(path)))
								{
									isCanceled = callback(path, fileAttributes);
									resultCount++;
								}
							}
						}
						else
							break;
					}
				}
			}
			catch (System.UnauthorizedAccessException) {}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Architect
Canada Canada
Sébastien Lorion is software architect as day job.

He is also a musician, actually singing outside the shower Smile | :)

He needs constant mental and emotional stimulation, so all of this might change someday ...

Comments and Discussions