Enumerate directories that match wildcard - c#

This is my folder structure:
c:\logs\v1\api1
c:\logs\v1\api2
c:\logs\v2\api1
c:\logs\v2\api2
c:\logs\other
I would like to get all folders that match this pattern:
c:\logs\v*\api*
So, what I want is to get list of theese:
c:\logs\v1\api1
c:\logs\v1\api2
c:\logs\v2\api1
c:\logs\v2\api2
This doesn't work:
var result = Directory.GetDirectories(#"c:\logs\v*\api*");
Because System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*\api*'' is thrown
This doesn't work:
var directory = #"c:\logs\v*\api*";
var rootDirectory = Directory.GetDirectoryRoot(directory);
var remainingPath = directory.Substring(rootDirectory.Length);
Console.WriteLine($"remainingPath: {remainingPath}");
var result = Directory.GetDirectories(rootDirectory, remainingPath);
Because System.IO.IOException: 'The filename, directory name, or volume label syntax is incorrect. : 'c:\logs\v*'' is thrown
This works:
public static IEnumerable<string> ResolveDirectories(string path)
{
if (path.Contains("*") || path.Contains("?"))
{
var parts = new Regex(#"[\\/](?=[^\\/]*[\*?])").Split(path, 2);
var searchRoot = parts[0];
var searchPatterns = parts[1].Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
foreach (var dir in ResolveWildcards(searchRoot, searchPatterns))
yield return dir;
}
else
{
yield return path;
}
}
public static IEnumerable<string> ResolveWildcards(string searchRoot, string[] searchPatterns)
{
if (Directory.Exists(searchRoot))
{
// use next pattern to search in a search root
var next = searchPatterns[0];
// leave the rest for recursion
var rest = searchPatterns.Skip(1).ToArray();
if (!searchRoot.EndsWith("\\"))
searchRoot += "\\";
foreach (var dir in Directory.EnumerateDirectories(searchRoot, next))
{
// if nothing left (last pattern) - return it
if (rest.Length == 0)
yield return dir;
else
{
// otherwise search with rest patterns in freshly found directory
foreach (var sub in ResolveWildcards(dir, rest))
yield return sub;
}
}
}
}
But I don't like how this is coded.
Thanks to #Alessandro_D'Andria I created this:
public static IEnumerable<string> ResolveDirectories(string path)
{
var parts = new Regex(#"[\\/](?=[^\\/]*[\*?])").Split(path, 2);
var root = parts[0];
var part = #".*\\" + parts[1].Replace(#"\", #"\\");
var regex = new Regex(part);
var dirs = Directory
.EnumerateDirectories(
root,
"*",
SearchOption.AllDirectories)
.Where(x => regex.IsMatch(x))
.ToList();
return dirs;
}
But both solutions are big mess. Is there any more elegant solution?

I think you are complicating, just using some regex and linq should be enough:
var regex = new Regex(#".*\\logs\\v\d+\\api\d+");
var dirs = Directory
.EnumerateDirectories(
#"C:\logs",
"*",
SearchOption.AllDirectories)
.Where(x => regex.IsMatch(x));

Related

How can I loop over sub folders in Assets folder?

string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
foreach(string path in subFolders)
{
paths.Add(path);
}
For example the subFolders is Assets/My Folder
but under My Folder there are many more subfolders.
AssetDatabase.GetSubFolders don't make recursive it's getting the first sub folder only.
I want to get all the sub folders recursive.
I tried :
List paths = new List();
foreach(string path in subFolders)
{
paths.Add(path);
}
but it's still giving me only the first sub folder.
This is how I'm getting the selected path name in the Assets :
[MenuItem("Assets/Get Path")]
private static string GetClickedDirFullPath()
{
string clickedAssetGuid = Selection.assetGUIDs[0];
string clickedPath = AssetDatabase.GUIDToAssetPath(clickedAssetGuid);
string clickedPathFull = Path.Combine(Directory.GetCurrentDirectory(), clickedPath);
FileAttributes attr = File.GetAttributes(clickedPathFull);
return attr.HasFlag(FileAttributes.Directory) ? clickedPathFull : Path.GetDirectoryName(clickedPathFull);
}
[MenuItem("Assets/Get Path")]
private static string GetPath()
{
string path = GetClickedDirFullPath();
int index = path.IndexOf("Assets");
string result = path.Substring(index);
return result;
}
You could simply make it recursive using List<T>.AddRange like
private static string[] GetSubFoldersRecursive(string root)
{
var paths = new List<string>();
// If there are no further subfolders then AssetDatabase.GetSubFolders returns
// an empty array => foreach will not be executed
// This is the exit point for the recursion
foreach (var path in AssetDatabase.GetSubFolders(root))
{
// add this subfolder itself
paths.Add(path);
// If this has no further subfolders then simply no new elements are added
paths.AddRange(GetSubFoldersRecursive(path));
}
return paths.ToArray();
}
So e.g.
[ContextMenu("Test")]
private void Test()
{
var sb = new StringBuilder();
var folders = SubFolders("Assets");
if(folders.Length > 0)
{
foreach (var folder in SubFolders("Assets"))
{
sb.Append(folder).Append('\n');
}
}
else
{
sb.Append(" << The given path has no subfolders! >>");
}
Debug.Log(sb.ToString());
}
will print out the entire project's folder structure.
For
I get
Assets/Example 1
Assets/Example 1/SubFolder A
Assets/Example 1/SubFolder B
Assets/Example 1/SubFolder C
Assets/Example 2
Assets/Example 2/SubFolder A
Assets/Example 2/SubFolder A/SubSubFolder A
So in your case it would be
string selectedPath = GetPath();
var folders = SubFolders(selectedPath);
foreach(var path in folders)
{
...
}
Try this code for get recursive folder path
//this is your code
string selectedPath = GetPath();
var subFolders = AssetDatabase.GetSubFolders(selectedPath);
List<string> paths = new List<string>();
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);
}
}
else
{
paths.add(selectedPath);
}
public void GetAllRecursiveFolder(string currentPath,ref List<string> paths)
{
var subFolders = AssetDatabase.GetSubFolders(currentPath);
if(subFolders != null)
{
foreach(string path in subFolders)
{
GetAllRecursiveFolder(path,ref paths);// Get recursive folder path, and stored in ref variable
}
}
else
{
paths.add(currentPath);
}
}

How to use OrderByDescending on Properties using IListFileItem?

I have following code which will return all list items (files and folders) of specific given azure storage path.
I want to filter it using OrderByDescending based on Property LastModified
How to achieve this ?
// Get list of all files/directories on the file share
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare = fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
var test = (fileList.OrderByDescending(t => t.Uri.AbsolutePath).FirstOrDefault());
I tried with casting but LastModified is null
fileList.ToList().ForEach(x => ((CloudFileDirectory)x).FetchAttributes());
GetAllSubDir(fileList.OrderByDescending(t => ((CloudFileDirectory)t).Properties.LastModified.Value).FirstOrDefault());
instead of Uri.AbsolutePath I want to use LastModified.
Have a try at following code. You need to get all files first because ListFilesAndDirectories only returns files and directory in a single level.
List<CloudFile> list = new List<CloudFile>();
public void Test()
{
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare =
fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
listFile(fileList);
var test = (from file in list
orderby file.Properties.LastModified descending
select file).FirstOrDefault();
}
// detect all files in the directory
public void listFile(IEnumerable<IListFileItem> results)
{
foreach (IListFileItem fileItem in results)
{
if (fileItem.GetType() == typeof(CloudFileDirectory))
{
CloudFileDirectory directory = (CloudFileDirectory)fileItem;
var res = directory.ListFilesAndDirectories();
listFile(res);
}
else
{
CloudFile file = (CloudFile)fileItem;
file.FetchAttributes();
list.Add(file);
}
}
}
public static void CheckDate()
{
CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["storageConnectionString"]);
CloudFileClient fileClient = cloudStorageAccount.CreateCloudFileClient();
CloudFileShare fileShare =
fileClient.GetShareReference(ConfigurationManager.AppSettings["shareName"]);
var sourceName = fileShare.GetRootDirectoryReference().GetDirectoryReference((ConfigurationManager.AppSettings["sourceName"]));
IEnumerable<IListFileItem> fileList = sourceName.ListFilesAndDirectories();
listFile(fileList);
var latestFile = (from file in filedataList
orderby file.Properties.LastModified descending
select file).FirstOrDefault();
Console.WriteLine(" LastModified Datetime - " + latestFile.Properties.LastModified.Value.DateTime);
}
public static void listFile(IEnumerable<IListFileItem> results)
{
foreach (var item in results)
{
if (item.GetType() == typeof(CloudFileDirectory))
{
CloudFileDirectory dir = (CloudFileDirectory)item;
dir.FetchAttributes();
dirList.Add(dir);
}
else
{
CloudFile file = (CloudFile)item;
file.FetchAttributes();
filedataList.Add(file);
}
}
if (dirList.Count > 0)
{
var latestDir = (from dir in dirList
orderby dir.Properties.LastModified descending
select dir).FirstOrDefault();
dirList.Clear();
var result = latestDir.ListFilesAndDirectories();
listFile(result);
}
}

Collect Directory and Sub Directories with mapping and index in a List<>

I want to collect the directory listing in a collection(a List<> perhaps)
my directory structure is like :
MainFolder\ParentFolder1\SubFolder1
\SubFolder2
\SubFolder3
MainFolder\ParentFolder2\SubFolder1
\SubFolder2
\SubFolder3
I want to list all the subfolders mapped to their parent directories.
Also, the records will have index of ParentFolder 0-n in MainFolder and index of SubFolder 0-n in each ParentFolder.
I did tried below but not yet achieved
lstParents = (from f in Directory.GetDirectories(MainFolder)
select Data
{
parent =f
}).ToList();
var lstSubDir = (from f in lstParents.Select(m => Directory.GetDirectories(m.parent).ToList());
You can use this overload of the GetDirectories method to find all subdirectories recursively:
var mainDirectory = new DirectoryInfo(#"C:\temp\MainFolder");
var subDirectories = mainDirectory.GetDirectories("*", SearchOption.AllDirectories);
Then you can map them into pairs of directory/parent like this:
var mappedDirectories = subDirectories.Select(sd => new { Parent=sd.Parent, Child=sd });
If you want to exclude the first level of subdirectories (ParentFolder1 and ParentFolder2, in your case) you can filter them like this:
var mappedDirectories = subDirectories
.Where(sd => sd.Parent.FullName != mainDirectory.FullName)
.Select(sd => new { Parent=sd.Parent, Child=sd });
EDIT after you've asked for indices:
You stated, that you'll always only have a nesting level of 2, the following piece of code will not work for deeper directory structures.
var mainDirectory = new DirectoryInfo(#"C:\temp\MainFolder");
var firstLevelDirectories = mainDirectory.GetDirectories().Select((f1,i) => new {
Parent = f1,
ParentIndex = i
});
var secondLevelDirectories = firstLevelDirectories
.SelectMany(f1 => f1.Parent.GetDirectories().Select((f2,i) => new {
f1.Parent,
f1.ParentIndex,
Child = f2,
ChildIndex = i
} ));
This will give you a list of records, each containing
the parent directory,
the parent directory index,
the child directory and
the child directory index within its parent.
Try this recursive algorithm.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Folders folders = new Folders(#"c:\temp", null);
Console.ReadLine();
}
}
public class Folders
{
public string path { get; set; }
List<string> files = new List<string>();
List<Folders> folders = new List<Folders>();
Folders parent = null;
public Folders(string path, Folders parent)
{
this.parent = parent;
this.path = path;
foreach (string folderPath in Directory.GetDirectories(path))
{
Folders newFolder = new Folders(folderPath, this);
folders.Add(newFolder);
}
files = Directory.GetFiles(path).ToList();
int pathlength = path.Length;
Boolean first = true;
Console.Write(path);
if (files.Count == 0) Console.WriteLine();
foreach (string file in files)
{
string shortname = file.Substring(file.LastIndexOf("\\") + 1);
if (first)
{
Console.WriteLine("\\" + shortname);
first = false;
}
else
{
Console.WriteLine(new string(' ', pathlength + 1) + shortname);
}
}
}
}
}
​

Efficiently retrieving and filtering files by using filename

i am a newbie hier, i try to retreive files by using filenames, which have the following definition:
Items number + Revision + lot number.pdf
For example:
1109093-A2 (85806S).pdf
1109093-A3 (85806S).pdf
1109092-A1 (85806S).pdf
1109092-A2 (85806S).pdf
for this sample file: 1109093-A2 (85806S).pdf
Items number: 1109093
Revision: -A2
End item number: (85806S)
for my search result, i am supose to have only this files.
1109093-A3 (85806S).pdf
1109092-A2 (85806S).pdf
i must have only files, with the actual Revision like the one up there( A3 ,A2).
But it not, still now i am getting all Files, how can i sort it by Revision please???
A1, A2, A3, A.... (Revisions) represents the selection criteria I should use. I wrote the follow function for this job.
private string[] GetFiles()
{
strSourcePath = textBox1.Text;
strTargetPath = textBox2.Text;
string fileName = string.Empty;
strExtension = "*).pdf";
string[] files = null;
if (Directory.Exists(strSourcePath))
{
files = Directory.GetFiles(strSourcePath, strExtension, SearchOption.AllDirectories);
var Result = "";
string joined = String.Join("# ", Result);
files = null;
Result = joined.Split('#');
files = Result.Where(file => Regex.IsMatch(Path.GetFileName(file), "^[0-9]+")).ToArray();
}
else
{
MessageBox.Show("Source path does not exist!");
}
return files ;
}
After you got the paths, you can parse the filename, extract revision/etc and sort based on your criteria.
This code parse as an anonymous class (for readability) and sort based on ItemNumber, Revision.
The anonymous class contains the path and item number/revision/end number info.
See the demo for complete example
var paths = new [] {
"1109093-A2 (85806S).pdf",
"1109093-A3 (85806S).pdf",
"1109092-A1 (85806S).pdf",
"1109092-A2 (85806S).pdf",
};
var result = paths.Select(x => {
var match = Regex.Match(x, #"(?<ItemsNumber>\d+)-(?<Revision>\w+)\s+\((?<EndItemNumber>\w+)\).pdf");
if (match.Success)
{
return new { ItemNumber = match.Groups[1].Value, Revision = match.Groups[2].Value, EndItemNumber = match.Groups[3].Value, Path = x };
}
else {
return new { ItemNumber = "", Revision = "", EndItemNumber = "", Path = x };
}
})
.OrderBy(x => x.ItemNumber).ThenBy(x => x.Revision);
demo: https://dotnetfiddle.net/47uZni
Using your template I wrote this function, but the return value is always the same - one item, but not a list as I expected. I do not know why. Did you have some idea?
private string[] SortFileName(string []TemP)
{
var paths = GetTheFileName(TemP);
List<string> TheCollection = new List<string>();
var result = paths.Select(x => {
var match = Regex.Match(x, #"(?<ItemsNumber>\d+)-(?<Revision>\w+)\s+\((?<EndItemNumber>\w+)\).pdf");
if (match.Success)
{
return new { ItemNumber = match.Groups[1].Value, Revision = match.Groups[2].Value, EndItemNumber = match.Groups[3].Value, Path = x };
}
else {
return new { ItemNumber = "", Revision = "", EndItemNumber = "", Path = x };
}
})
.GroupBy(x => x.ItemNumber)
.Select(x => x.OrderByDescending(y => y.Revision).First());
foreach (var item in result)
{
TheCollection.Add(item.Path.ToString());
}
return TheCollection.ToArray();
}
PS: GetTheFileName(TemP); return an array with more than 130 items. thanks for the coming help.

How to compare two folders for similar files based on name in C#?

I have two folders A and B..Inside A multiple files are there and inside B multiple files are there..I have to check files in A with files in B for identical files...
I tried like this for a particular file name
void DirSearch(string sDir)
{
List<string> lstFilesFound = new List<string>();
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetFiles(d,"MsBuild_Tracker.proj")
{
lstFilesFound.Add(f);
}
DirSearch(d);
}
}
It is working..I tried like this for two folders
foreach (string d in Directory.GetDirectories(sDir))
{
foreach (string f in Directory.GetDirectories(dDir))
{
foreach (string g in Directory.GetFiles(d, f))
{
lstFilesFound.Add(g);
}
DirSearch(d, f);
}
}
It is not working...Any suggestion??
If you're using .NET 4, you can use DirectoryInfo and EnumerateFiles(). Then you can use LINQ to join the two directories to get the common files between the two directories.
var dir1 = new DirectoryInfo(#"c:\temp1");
var dir2 = new DirectoryInfo(#"c:\temp2");
var filesinboth = from f1 in dir1.EnumerateFiles()
join f2 in dir2.EnumerateFiles() on f1.Name equals f2.Name
select f1.Name;
or you can use where if you want additional conditions to apply.
var filesinboth = from f1 in dir1.EnumerateFiles()
from f2 in dir2.EnumerateFiles()
where f1.Name == f2.Name // and some other condition
select f1.Name;
These will both give you stream of strings. If you need the actual FileInfo instances, change the select part of the query to return f1 instead of f1.Name.
If you're using .NET 3.5, you need to use GetFiles() instead, which returns FileInfo[]. So the queries will look like this:
var filesinboth = from f1 in dir1.GetFiles()
join f2 in dir2.GetFiles() on f1.Name equals f2.Name
select f1.Name;
and
var filesinboth = from f1 in dir1.GetFiles()
from f2 in dir2.GetFiles()
where f1.Name == f2.Name // and some other condition
select f1.Name;
Why don't use just something like this (without recursion) ?
public static IEnumerable<string> GetMachingFiles(string pathA, string pathB)
{
var matchingFiles = new HashSet<string>();
var allAfiles = Directory.GetFiles(pathA, "*", SearchOption.AllDirectories);
foreach (var file in allAfiles)
{
foreach (var mathcFile in Directory.GetFiles(pathB, Path.GetFileName(file), SearchOption.AllDirectories))
matchingFiles.Add(mathcFile);
}
return matchingFiles;
}
Of course this solution suffers a performance decay in case of many files, because Directory.GetFiles navigates all files even when you pass a restrictive pattern.
To be more faster you could use LINQ as pointed out in Brian Rasmussen's answer
EDIT:
a faster example using LINQ (.NET 3.5):
public static IEnumerable<string> GetMachingFilesFast(string pathA, string pathB)
{
DirectoryInfo dirA = new DirectoryInfo(pathA);
DirectoryInfo dirB = new DirectoryInfo(pathB);
var filesA = dirA.GetFiles("*",SearchOption.AllDirectories);
var filesB = dirB.GetFiles("*", SearchOption.AllDirectories);
var matchingFiles =
filesA.Where(fA => filesB.Any(
fB => fA.Name == fB.Name
// && fA.LastWriteTime == fB.LastWriteTime
)
)
.Select(x => x.Name);
return matchingFiles;
}
try below code , you need to change path of files
DirectoryInfo dinfoTemp1 = new DirectoryInfo(#"C:\\Temp1");
DirectoryInfo dinfoTemp2 = new DirectoryInfo(#"C:\\Temp2");
FileInfo[] lstTemp1 = dinfoTemp1.GetFiles();
List<string> ui = lstTemp1.Where(
x => dinfoTemp2.GetFiles().
Where(y => y.Name.Contains(x.Name)).Count() > 0).
Select(x=>x.Name).ToList();
What you are basically doing is:
setting directory to var d like C://
Setting directory to var f like My Documents
Getting files that have the name My Documents in C://
and if you find any which I highly doubt, you add it to your list.
The first one works because;
sets the directory to var d like C://
gets the file that is named MsBuild_Tracker.proj in C://
adds it to the list.
Tell us what you need and maybe we can help..
Maybe compare (for a non-linq version) --
namespace RecursiveDirCompare
{
class Program
{
static List initialFiles = new List();
static string initRoot = #"root";
static string initCompare = #"compare";
static void Main(string[] args)
{
Directory.SetCurrentDirectory( #"C:\Temp\test\");
initRoot = #"root";// args[0];
initCompare = #"compare";// args[1];
AddFilesToInitialList(initRoot);
CompareWithInitialList(initCompare);
Console.ReadKey();
}
static void AddFilesToInitialList(string root)
{
foreach (string file in Directory.GetFiles(root))
{
initialFiles.Add(file.Replace(initRoot, ""));
}
foreach (string directory in Directory.GetDirectories(root))
{
AddFilesToInitialList(directory);
}
}
static void CompareWithInitialList(string root)
{
foreach (string file in Directory.GetFiles(root))
{
if(initialFiles.Contains(file.Replace(initCompare, "")))
{
Console.WriteLine(file + " is found in both");
}
}
foreach (string directory in Directory.GetDirectories(root))
{
CompareWithInitialList(directory);
}
}
}
}

Categories