How can I search a Path like that in C#:
"C:\MyApp\*\log"
I want to get all Directories that matches that search pattern.
Example result:
C:\MyApp\20171009\log
C:\MyApp\20171008\log
C:\MyApp\20171007\log
In Powershell it works with get-item
Try this iterator-based file functions:
var path = #"C:\temp";
foreach (var file in Directory.EnumerateFiles(path, "*.log", SearchOption.AllDirectories))
{
Console.WriteLine(file);
}
For more informations show here
If you are trying to just get the directories with Name Log which match the pattern C:\MyApp*\log, following code should help:
var dirs = Directory.EnumerateDirectories(#"C:\Temp\","log", SearchOption.AllDirectories);
Notice that search pattern is the name of directory and not any file name or file extension
I found a solution for my Problem.
I modified it for Directory-Use.
public static List<string> GetAllMatchingPaths(string pattern)
{
char separator = Path.DirectorySeparatorChar;
string[] parts = pattern.Split(separator);
if (parts[0].Contains('*') || parts[0].Contains('?'))
throw new ArgumentException("path root must not have a wildcard", nameof(parts));
return GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(1)), parts[0]);
}
private static List<string> GetAllMatchingPathsInternal(string pattern, string root)
{
char separator = Path.DirectorySeparatorChar;
string[] parts = pattern.Split(separator);
for (int i = 0; i < parts.Length; i++)
{
// if this part of the path is a wildcard that needs expanding
if (parts[i].Contains('*') || parts[i].Contains('?'))
{
// create an absolute path up to the current wildcard and check if it exists
var combined = root + separator + String.Join(separator.ToString(), parts.Take(i));
if (!Directory.Exists(combined))
return new List<string>();
if (i == parts.Length - 1) // if this is the end of the path (a file name)
{
return ( List<string> ) Directory.EnumerateFiles(combined, parts[i], SearchOption.TopDirectoryOnly);
}
else // if this is in the middle of the path (a directory name)
{
var directories = Directory.EnumerateDirectories(combined, parts[i], SearchOption.TopDirectoryOnly);
List<string> pts = new List<string>();
foreach ( string directory in directories )
{
foreach ( string item in GetAllMatchingPathsInternal(String.Join(separator.ToString(), parts.Skip(i + 1)), directory))
{
pts.Add(item);
}
}
return pts;
}
}
}
Related
Using SQL Server 2014 \ VS 2019. I have the below C# script task to delete files in a folder older than x number of days, and this works.
public void Main()
{
int RetentionPeriod = Convert.ToInt32(Dts.Variables["$Package::FileRententionDays"].Value.ToString());
string directoryPath = Dts.Variables["CSV_ArchivePath"].Value.ToString();
string[] oldFiles = System.IO.Directory.GetFiles(directoryPath, "*.*");
foreach (string currFile in oldFiles)
{
FileInfo currFileInfo = new FileInfo(currFile);
if (currFileInfo.LastWriteTime < (DateTime.Now.AddDays(-RetentionPeriod)))
{
currFileInfo.Delete();
}
}
Dts.TaskResult = (int)ScriptResults.Success;
}
However, how do I modify to just say, delete all files in the directory where the filenames begins with 'ABC'?
Define your start with "PREFIX" in a string something like StartsWithPrefix. Use the String.StartsWith Method to check if the FileInfo Name has the defined prefix needed to meet the requirements.
int RetentionPeriod = Convert.ToInt32(Dts.Variables["$Package::FileRententionDays"].Value.ToString());
string directoryPath = Dts.Variables["CSV_ArchivePath"].Value.ToString();
string[] oldFiles = System.IO.Directory.GetFiles(directoryPath, "*.*");
string StartsWithPrefix = "ABC";
foreach (string currFile in oldFiles)
{
FileInfo currFileInfo = new FileInfo(currFile);
if (currFileInfo.LastWriteTime < (DateTime.Now.AddDays(-RetentionPeriod))
&& currFileInfo.Name.StartsWith(StartsWithPrefix))
{
currFileInfo.Delete();
}
}
https://learn.microsoft.com/en-us/dotnet/api/system.string.startswith?view=netcore-3.1
https://learn.microsoft.com/en-us/dotnet/api/system.io.fileinfo.name?view=netcore-3.1
I have code that steps through a main directory and all the sub directories. The images in each sub directories needs to be renamed as per the folder it is ins name.
C:\Users\alle\Desktop\BillingCopy\uploaded 27-02\\Batch002-190227010418829\PPA14431564096\File1.png
should rename to
C:\Users\alle\Desktop\BillingCopy\uploaded 27-02\Batch002-190227010418829\PPA14431564096\PPA14431564096.png
I can see the code is stepping through every thing but the image isn't beeing renamed and I can't see where I went wrong
while(isTrue)
{
try
{
//write your code here
string filename1 = "1.tif";
string newFileName = "allen.tif";
string[] rootFolder = Directory.GetDirectories(#"C:\Users\alle\Desktop\BillingCopy");
foreach(string dir in rootFolder)
{
string[] subDir1 = Directory.GetDirectories(dir);
foreach(string subDir in subDir1)
{
string[] batchDirList = Directory.GetDirectories(subDir);
foreach(string batchDir in batchDirList)
{
string[] waybillNumberDir = Directory.GetDirectories(batchDir);
foreach(string hawbDir in waybillNumberDir)
{
string waybillNumber = Path.GetDirectoryName(hawbDir);
string[] getFileimages = Directory.GetFiles(hawbDir);
foreach(string imgInDir in getFileimages)
{
File.Copy(imgInDir, Path.Combine(#"C:\Users\alle\Desktop\Copy", string.Format("{0}.{1}", waybillNumber, Path.GetExtension(imgInDir))));
}
}
}
}
}
File.Copy(Path.Combine("source file", filename1), Path.Combine("dest path",
string.Format("{0}{1}", Path.GetFileNameWithoutExtension(newFileName), Path.GetExtension(newFileName))), true);
}
catch { }
}
When querying you can try using Linq to obtain the required data:
// All *.png files in all subdirectories
string rootDir = #"C:\Users\alle\Desktop\BillingCopy";
var agenda = Directory
.EnumerateFiles(rootDir, "*.png", SearchOption.AllDirectories)
.Select(file => new {
oldName = file,
newName = Path.Combine(
Path.GetDirectoryName(file),
new DirectoryInfo(Path.GetDirectoryName(file)).Name + Path.GetExtension(file))
})
.ToArray();
Then we can move (not copy) the files:
foreach (var item in agenda)
File.Move(item.oldName, item.newName);
I need find the specific file/folder on my hard drive.
For example i need find a file (do1.bat) and then store the path of the file. But i dont know where can it be stored, so i have to scan all hard drive.
How can i use C# for this?
A simple way would be
var results = Directory.GetFiles("c:\\", "do1.bat", SearchOption.AllDirectories);
This would recurse through all directory and collect all files named do1.bat. Unfortunatly this will not work on complete c:\ since it will throw exceptions if you don't have access to a directory, which surely will happen.
So this is a recursive version:
private static void FindFile(DirectoryInfo currentDirectory, string pattern, List<FileInfo> results)
{
try
{
results.AddRange(currentDirectory.GetFiles(pattern, SearchOption.TopDirectoryOnly));
foreach (DirectoryInfo dir in currentDirectory.GetDirectories("*", SearchOption.TopDirectoryOnly).Where(d => d.Name != "." && d.Name != ".."))
FindFile(dir, pattern, results);
}
catch
{
// probably no access to directory
}
}
This recurses through the directory tree and tries to get the files in a directory and then all subdirectories (except . and ..).
You can use it this way:
DirectoryInfo d = new DirectoryInfo("c:\\");
List<FileInfo> results = new List<FileInfo>();
FindFile(d, "do1.bat", results);
This will find all files named do1.bat in any subdirectory of C:\\ and enlist the FileInfos in the results list.
this should provide you a list of files, matching your search pattern
string[] Result = Directory.GetFiles(#"C:\", "do1.bat", SearchOption.AllDirectories);
Refer: https://msdn.microsoft.com/en-us/library/07wt70x2(v=vs.110).aspx
List<string> lstfilepaths = new List<string>();
public static void ProcessDirectory(string targetDirectory)
{
// Process the list of files found in the directory.
string [] fileEntries = Directory.GetFiles(targetDirectory);
foreach(string fileName in fileEntries) // included as per your logic
{
if(fileName == "do1.bat")
{
ProcessFile(fileName);
}
}
// Recurse into subdirectories of this directory.
string [] subdirectoryEntries = Directory.GetDirectories(targetDirectory);
foreach(string subdirectory in subdirectoryEntries)
ProcessDirectory(subdirectory);
}
public static void ProcessFile(string path)
{
lstfilepaths.Add(path);
}
For one file:
public string FindFileByName(string fileName, string searchPath)
{
string resultPath = null;
DirectoryInfo directoryInWhichToSearch = new DirectoryInfo(searchPath);
FileInfo foundFile = directoryInWhichToSearch.GetFiles(fileName, SearchOption.AllDirectories)[0];
resultPath = foundFile.FullName;
return resultPath;
}
You can then use it like this:
string fileFullPath = FindFileByName("do1.bat", #"C:\");
I have a folder that is filled with dwg files so I just need to find the latest version of a File or if a File has no versions then copy it to a directory. For example here are three files:
ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwg
ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwg
Notice the difference is one file has a _1 and another has a _2 so the latest file here is the _2. I need to keep the latest file and copy it to a directory. Some files will not have different versions so those can be copied. I cannot focus on the creation date of the file or the modified date because in many instances they are the same so all I have to go on is the file name itself. I'm sure there is a more efficient way to do this than what I will post below.
DirectoryInfo myDir = new DirectoryInfo(#"H:\Temp\Test");
var Files = myDir.GetFiles("*.dwg");
string[] fileList = Directory.GetFiles(#"H:\Temp\Test", "*FINAL*", SearchOption.AllDirectories);
ArrayList list = new ArrayList();
ArrayList WithUnderscores = new ArrayList();
string nameNOunderscores = "";
for (int i = 0; i < fileList.Length; i++)
{
//Try to get just the filename..
string filename = fileList[i].Split('.')[0];
int position = filename.LastIndexOf('\\');
filename = filename.Substring(position + 1);
filename = filename.Split('_')[0];
foreach (FileInfo allfiles in Files)
{
var withoutunderscore = allfiles.Name.Split('_')[0];
withoutunderscore = withoutunderscore.Split('.')[0];
if (withoutunderscore.Equals(filename))
{
nameNOunderscores = filename;
list.Add(allfiles.Name);
}
}
//If there is a number after the _ then capture it in an ArrayList
if (list.Count > 0)
{
foreach (string nam in list)
{
if (nam.Contains("_"))
{
//need regex to grab numeric value after _
var match = new Regex("_(?<number>[0-9]+)").Match(nam);
if (match.Success)
{
var value = match.Groups["number"].Value;
var number = Int32.Parse(value);
WithUnderscores.Add(number);
}
}
}
int removedcount = 0;
//Whats the max value?
if (WithUnderscores.Count > 0)
{
var maxval = GetMaxValue(WithUnderscores);
Int32 intmax = Convert.ToInt32(maxval);
foreach (FileInfo deletefile in Files)
{
string shorten = deletefile.Name.Split('.')[0];
shorten = shorten.Split('_')[0];
if (shorten == nameNOunderscores && deletefile.Name != nameNOunderscores + "_" + intmax + ".dwg")
{
//Keep track of count of Files that are no good to us so we can iterate to next set of files
removedcount = removedcount + 1;
}
else
{
//Copy the "Good" file to a seperate directory
File.Copy(#"H:\Temp\Test\" + deletefile.Name, #"H:\Temp\AllFinals\" + deletefile.Name, true);
}
}
WithUnderscores.Clear();
list.Clear();
}
i = i + removedcount;
}
else
{
//This File had no versions so it is good to be copied to the "Good" directory
File.Copy(#"H:\Temp\SH_Plats\" + filename, #"H:\Temp\AllFinals" + filename, true);
i = i + 1;
}
}
I've made a Regex based solution, and apparently come late to the party in the meantime.
(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\.dwg
this regex will recognise the fileName and version and split them into groups, a pretty simple foreach loop to get the most recent files in a dictionary (cos I'm lazy) and then you just need to put the fileNames back together again before you access them.
var fileName = file.Key + "_" + file.Value + ".dwg"
full code
var files = new[] {
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_1.dwg",
"ABBIE 08-10 #6-09H4 FINAL 06-12-2012_2.dwg",
"Second File.dwg",
"Second File_1.dwg",
"Third File.dwg"
};
// regex to split fileName from version
var r = new Regex( #"(?<fileName>[A-Za-z0-9-# ]*)_?(?<version>[0-9]+)?\.dwg" );
var latestFiles = new Dictionary<string, int>();
foreach (var f in files)
{
var parsedFileName = r.Match( f );
var fileName = parsedFileName.Groups["fileName"].Value;
var version = parsedFileName.Groups["version"].Success ? int.Parse( parsedFileName.Groups["version"].Value ) : 0;
if( latestFiles.ContainsKey( fileName ) && version > latestFiles[fileName] )
{
// replace if this file has a newer version
latestFiles[fileName] = version;
}
else
{
// add all newly found filenames
latestFiles.Add( fileName, version );
}
}
// open all most recent files
foreach (var file in latestFiles)
{
var fileToCopy = File.Open( file.Key + "_" + file.Value + ".dwg" );
// ...
}
You can use this Linq query with Enumerable.GroupBy which should work(now tested):
var allFiles = Directory.EnumerateFiles(sourceDir, "*.dwg")
.Select(path => new
{
Path = path,
FileName = Path.GetFileName(path),
FileNameWithoutExtension = Path.GetFileNameWithoutExtension(path),
VersionStartIndex = Path.GetFileNameWithoutExtension(path).LastIndexOf('_')
})
.Select(x => new
{
x.Path,
x.FileName,
IsVersionFile = x.VersionStartIndex != -1,
Version = x.VersionStartIndex == -1 ? new Nullable<int>()
: x.FileNameWithoutExtension.Substring(x.VersionStartIndex + 1).TryGetInt(),
NameWithoutVersion = x.VersionStartIndex == -1 ? x.FileName
: x.FileName.Substring(0, x.VersionStartIndex)
})
.OrderByDescending(x => x.Version)
.GroupBy(x => x.NameWithoutVersion)
.Select(g => g.First());
foreach (var file in allFiles)
{
string oldPath = Path.Combine(sourceDir, file.FileName);
string newPath;
if (file.IsVersionFile && file.Version.HasValue)
newPath = Path.Combine(versionPath, file.FileName);
else
newPath = Path.Combine(noVersionPath, file.FileName);
File.Copy(oldPath, newPath, true);
}
Here's the extension method which i'm using to determine if a string is parsable to int:
public static int? TryGetInt(this string item)
{
int i;
bool success = int.TryParse(item, out i);
return success ? (int?)i : (int?)null;
}
Note that i'm not using regex but string methods only.
Try this
var files = new My.Computer().FileSystem.GetFiles(#"c:\to\the\sample\directory", Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg");
foreach (String f in files) {
Console.WriteLine(f);
};
NB: Add a reference to Microsoft.VisualBasic and use the following line at the beginning of the class:
using My = Microsoft.VisualBasic.Devices;
UPDATE
The working sample[tested]:
String dPath=#"C:\to\the\sample\directory";
var xfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dwg").Where(c => Regex.IsMatch(c,#"\d{3,}\.dwg$"));
XElement filez = new XElement("filez");
foreach (String f in xfiles)
{
var yfiles = new My.Computer().FileSystem.GetFiles(dPath, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, string.Format("{0}*.dwg",System.IO.Path.GetFileNameWithoutExtension(f))).Where(c => Regex.IsMatch(c, #"_\d+\.dwg$"));
if (yfiles.Count() > 0)
{
filez.Add(new XElement("file", yfiles.Last()));
}
else {
filez.Add(new XElement("file", f));
};
};
Console.Write(filez);
Can you do this by string sort? The only tricky part I see here is to convert the file name to a sortable format. Just do a string replace from dd-mm-yyyy to yyyymmdd. Then, sort the the list and get the last record out.
This is what you want considering fileList contain all file names
List<string> latestFiles=new List<string>();
foreach(var groups in fileList.GroupBy(x=>Regex.Replace(x,#"(_\d+\.dwg$|\.dwg$)","")))
{
latestFiles.Add(groups.OrderBy(s=>Regex.Match(s,#"\d+(?=\.dwg$)").Value==""?0:int.Parse(Regex.Match(s,#"\d+(?=\.dwg$)").Value)).Last());
}
latestFiles has the list of all new files..
If fileList is bigger,use Threading or PLinq
Using C# (.NET), how can I search a file system given a directory search mask like this: (?)
\\server\Scanner\images\*Images\*\*_*
For example, I need to first find all top-level directories:
\\server\Scanner\images\Job1Images
\\server\Scanner\images\Job2Images
...then I need to procede further with the search mask:
\\server\Scanner\images\Job1Images\*\*_*
\\server\Scanner\images\Job2Images\*\*_*
This doesn't seem too complicated but I can't figure it out for the life of me...
As mentioned above, I'm using C# and .NET. The search can be trying to locate directories or files. (i.e. *.txt, or <*Directory>)
Like this:
Top Level Directories:
//get Top level
string[] TopLevel = Directory.GetDirectories(path);
And then you will have to do a resursive function of this folders using wildcard pattern,
for example:
// Only get subdirectories that begin with the letter "p."
string pattern = "p*";
string[] dirs = folder.GetDirectories(path, pattern);
I suggest you play with wildcards to get the array output and you will figure out
which is the best way, if using resursive function or directly quering paths.
Edit: Ahh, new functionality with .NET 4 so you don't have to do a recursive function (Thanks Matthew Brubaker)
IEnumerable<String> matchingFilePaths2 = System.IO.Directory.EnumerateFiles(#"C:\some folder to start in", filePatternToMatchOn, System.IO.SearchOption.AllDirectories);
First Answer:
//get all files that have an underscore - searches all folders under the start folder
List<String> matchingFilePaths = new List<string>();
String filePatternToMatchOn = "*_*";
FileUtilities.GetAllFilesMatchingPattern(#"C:\some folder to start in", ref matchingFilePaths, filePatternToMatchOn);
...
public static void GetAllFilesMatchingPattern(String pathToGetFilesIn, ref List<String> fullFilePaths, String searchPattern)
{
//get all files in current directory that match the pattern
String[] filePathsInCurrentDir = Directory.GetFiles(pathToGetFilesIn, searchPattern);
foreach (String fullPath in filePathsInCurrentDir)
{
fullFilePaths.Add(fullPath);
}
//call this method recursively for all directories
String[] directories = Directory.GetDirectories(pathToGetFilesIn);
foreach (String path in directories)
{
GetAllFilesMatchingPattern(path, ref fullFilePaths, searchPattern);
}
}
public static IEnumerable<string> GetImages()
{
//For each "*Image" directory
foreach (var jobFolder in Directory.EnumerateDirectories(#"\\server\Scanner\images", "*Images"))
{
//For each first level subdirectory
foreach (var jobSubFolder in Directory.EnumerateDirectories(jobFolder))
{
//Enumerate each file containing a '_'
foreach (var filePath in Directory.EnumerateFiles(jobSubFolder, "*_*", SearchOption.TopDirectoryOnly))
{
yield return filePath;
}
}
}
}
Only the files from the first level subdirectories of each "*Image" directory are enumerated.
Finally you can use it with:
foreach (var path in GetImages())
{
Console.WriteLine(path);
}
There is a C# procedure where you can search folder by path pattern with wildcards like * and ?.
Example if path pattern C:\Folder?*\Folder2 is passed to the procedru, then a list of folder path will be returned
C:\Folder1\A\Folder2
C:\FolderA\B\Folder2
...
and so on
static List<string> GetFoldersByPathPattern(string folderPathPattern)
{
List<string> directories = new List<string>();
directories.Add("");
string[] folderParts = folderPathPattern.Split(new char[] { '\\' }, StringSplitOptions.None);
foreach (string folderPart in folderParts)
{
if (folderPart.Contains('*') || folderPart.Contains('?'))
{
List<string> newDirectories = new List<string>();
foreach (string directory in directories)
{
foreach (string newDirectory in Directory.GetDirectories(directory, folderPart))
{
newDirectories.Add(newDirectory);
}
}
directories = newDirectories;
}
else
{
for (int i = 0; i < directories.Count(); i++)
{
directories[i] = directories[i] + folderPart + "\\";
}
}
}
return directories;
}