Use a switch statement to create file directories? - c#

I'm creating an app that's going to be installed on a number of devices and I'd like to automate the setup of the file system on each device's local disk as much as possible. Rather than use dozens of if statements is there a more streamlined way to do this using a switch statement?
if (System.IO.Directory.Exists(arctopithecusGalleryPath) == false)
{
System.IO.Directory.CreateDirectory(arctopithecusGalleryPath);
}

How about creating a method for that:
public void CreateIfNotExists(string path)
{
if (System.IO.Directory.Exists(path) == false)
{
System.IO.Directory.CreateDirectory(path);
}
}
And then use it in your code like this:
CreateIfNotExists(arctopithecusGalleryPath);
Or if you have multiple directories you can add them to list and call this method inside foreach statement:
List<string> folders = new List<string>();
folders.Add("a folder to create");
// add more folders
foreach(var folder in folders)
{
CreateIfNotExists(folder);
}

Store variables in array & loop them to avoid multiple IFs.
string[] arr1 = new string[] { arctopithecusGalleryPath, arctopithecusGalleryPath1, arctopithecusGalleryPath3 };
for (int i = 0; i < arr1.Length; i++)
{
if (System.IO.Directory.Exists(array[i]) == false){
System.IO.Directory.CreateDirectory(array[i]);
}

Related

Creating Subdirectory function in C#

I am currently attempting to create a function code that creates a subdirectory inside a user-specific path by having the user input the Directory path and then in main use the Directory.GetDirectories(arwgs) function to get a string array of there path.
This code works for the first attempt but after rerunning it again it creates a folder in same directory in the that I don't want to do again.
Good:
Directorys Created S:\Shop....\600\UnitCalFall
Bad:
Directorys Created S:\Shop\600\UnitCalFall\UnitCalFall
or
Directorys Created S:\Shop\600\UnitCalFall\UnitCalDone
I am trying to make the function as fast and integrative as possible so incase the user wants to create more than one or two folders.
The code is shown below:
static void UnitCalFolderCheck(string[] sDirectoryPath, string[] NewFolder)
{
//possible method can be constructed that checks for if a option UnitCallFolder has been created
for (int index = 0; index < sDirectoryPath.Length; index++)
{
//for each directory in the path if a folder named as UnitCalDONE in order to store CSV files data that has already been stored and conducted.
//ig a foldered labeled as such is already created then do not create this folder
string sCurrentPath = sDirectoryPath[index];
//check if current directory path already is created by the newfolder length path
//NEED TO CREATE A VARIABLE THAT CHECKS IF ANY OF THE SUBSTRINGS ARE TRUE AND IF SO DO NOT CHECK FOR NEW DIRECTORY
bool bexist = false;
//Console.WriteLine(sCurrentPath);
//also check if a the current path also has the UnitCalFolder Done already. This is because the newDirpath
//Will be a duplication of each folder and this can cause problems for the for loop
//append for each dirpath the folder information
for (int i = 0; i < NewFolder.Length; i++)
{
int NewFolderLength = NewFolder[i].Length;
string sNewDirPath = sCurrentPath + NewFolder[i];
string substring = sCurrentPath.Substring(sCurrentPath.Length - NewFolderLength);
//looping around the new possible created folders based on the substring paths
foreach (string x in NewFolder)
{
//THIS DOESNT CHECK IF FOLDER IS DIFFERENT FROM THE OTHER CONTAINER
// Console.WriteLine(x);
if (!substring.Contains(x)) //not working propery
{
bexist = true;
}
else
{
bexist = false;
}
}
if (!Directory.Exists(sNewDirPath) && (bexist == true) )
{
Directory.CreateDirectory(sNewDirPath);
Console.WriteLine("Directorys Created" + sNewDirPath);
}
}
}
}
*A crude way of fixing but when looking back this can work for folders with the suffix "UnitCal". At least for my directory. Not the most elegant but works.
static void UnitCalFolderCheck(string[] sDirectoryPath, string[] NewFolder)
{
//possible method can be constructed that checks for if a option UnitCallFolder has been created
for (int index = 0; index < sDirectoryPath.Length; index++)
{
//for each directory in the path if a folder named as UnitCalDONE in order to store CSV files data that has already been stored and conducted.
//ig a foldered labeled as such is already created then do not create this folder
string sCurrentPath = sDirectoryPath[index];
//Console.WriteLine(sCurrentPath);
//int[] iexist = new int[NewFolder.Count()]; //if substring exist already then dont create new directory
//int inotexist = 0;
string sNewDirPath;
string FolderIndexPath = "";
//for every new folder in the path check if the directory with substring already exist
for(int x = 0; x < NewFolder.Length; x++)
{
int NewFolderLength = NewFolder.Length; //length of the new folder to append to newdirpath string
//string substring = sCurrentPath.Substring(sCurrentPath.Length - NewFolderLength);
//UnitCalDone folder first iteration
//UNitCalFall folder secnond iteration
Console.WriteLine("========================================================================");
Console.WriteLine(sCurrentPath);
Console.WriteLine(NewFolder[x]);
if (!sCurrentPath.Contains("UnitCal"))
{
// iexist[x] = 0;
sNewDirPath = sCurrentPath + NewFolder[x];
// Determine whether the directory exists.
if (!Directory.Exists(sNewDirPath))
{
//check if new path already exist if so then do nothing
Console.WriteLine("NEWPATH->>>");
//Directory.CreateDirectory(sNewDirPath);
Console.WriteLine(sNewDirPath); //check that none of this values contain the selected values
}
}
else
{
//do nothing
}
}
}//end of for loop method
}//end of unitCalFolderCheckr code here*

How can i get all files on disk with a specific extension using 'Directory.getFiles' and save them in a list

I'm doing a console project whose goal is to search the entire disk for all files with the extension '.config'
I've tried something like:
foreach (string file in Directory.GetFiles("C:\\", "*.config", SearchOption.AllDirectories))
{
Console.WriteLine(file);
Console.ReadLine();
}
but gave me an error "denied access to path (...)".
On the internet I found this code:
Stack<string> pending = new Stack<string>();
pending.Push("C:\\");
while (pending.Count != 0)
{
var path = pending.Pop();
string[] next = null;
try
{
next = Directory.GetFiles(path, "*.config");
}
catch { }
if (next != null && next.Length != 0)
foreach (var file in next)
{
Console.WriteLine(file);
Console.ReadLine();
}
try
{
next = Directory.GetDirectories(path);
foreach (var subdir in next) pending.Push(subdir);
}
catch { }
}
but it just shows the path clicking always in 'enter' and I want to save those files/path in a list.
Someone can help?
There are two things you can do to improve that code:
Use Directory.EnumerateFiles() and Directory.EnumerateDirectories() to avoid making a copy of the names of all the files in each directory.
Make the return type of the method IEnumerable<string> to make it easier to consume.
We also need to be very careful about exceptions caused by attempting to access protected files and directories. The code below is also complicated by the fact that you're not allowed to yield return from inside a try/catch block, so we have to rearrange the code somewhat.
(Also note that we have to dispose the enumerator returned from .GetEnumerator(); normally this is done automatically when you use foreach, but in this case we can't - because of having to avoid doing yield return in a try/catch - so we have to use using to dispose it.)
Here's a modification of your original code to do this:
public static IEnumerable<string> GetFiles(string root, string spec)
{
var pending = new Stack<string>(new []{root});
while (pending.Count > 0)
{
var path = pending.Pop();
IEnumerator<string> fileIterator = null;
try
{
fileIterator = Directory.EnumerateFiles(path, spec).GetEnumerator();
}
catch {}
if (fileIterator != null)
{
using (fileIterator)
{
while (true)
{
try
{
if (!fileIterator.MoveNext()) // Throws if file is not accessible.
break;
}
catch { break; }
yield return fileIterator.Current;
}
}
}
IEnumerator<string> dirIterator = null;
try
{
dirIterator = Directory.EnumerateDirectories(path).GetEnumerator();
}
catch {}
if (dirIterator != null)
{
using (dirIterator)
{
while (true)
{
try
{
if (!dirIterator.MoveNext()) // Throws if directory is not accessible.
break;
}
catch { break; }
pending.Push(dirIterator.Current);
}
}
}
}
}
As an example, here's how you could use a console app to list all the accessible ".txt" files on the "C:\" drive:
static void Main()
{
foreach (var file in GetFiles("C:\\", "*.txt"))
{
Console.WriteLine(file);
}
}
Replace the lines
Console.WriteLine(file);
Console.ReadLine();
with a method to store them in a list.
For example
foundFiles.Add(file);
Then when the method is done, you can read all found file paths from this list.
Notes:
This will not yield all files on the system that match the filter.
Only files where your application has access to their respective directory are found this way.
For example the Windows directory and user directories of other users are usually protected. (assuming you run on Windows)
Keep in mind, that some files might be protected independently of their directory.
So when trying to read them, also consider the fact, that the read might fail.
Just encompass the read with a try catch.
Regarding the error "denied access to path (...)", sometimes you have to run Visual Studio as an a administrator in order to access some folders in the C:\ drive.

Scanning for Java executable

I'd like my program to scan the user's hard drive for java.exe.
I was considering using a for-loop and then going through each directory and then check if the directory names match the ones I would set up and then check in those for the java exe, but I'm sure there is a much more efficient way of doing so.
Any ideas on how to approach this?
Edit:
I've gone ahead and done some foreach loops, but it isn't going too well. I'm probably missing something:
// Scan for Java executable (java.exe)
foreach (String dir in Directory.GetDirectories("C:/"))
{
if (dir == "Program Files")
{
foreach (String _dir in Directory.GetDirectories(dir)) {
if (_dir == "Java")
{
foreach (String javaDir in Directory.GetDirectories(_dir))
{
if (javaDir == "jre7")
{
foreach (String binDir in Directory.GetDirectories(javaDir)) {
if (binDir == "bin")
{
foreach (String file in Directory.GetFiles(binDir))
{
if (file == "java.exe")
{
javaExe = file;
}
}
}
}
}
}
}
}
}
}
You are looking for java.exe. So
Firstly you should look for directory where oracle always install it's java.exe
which should be at
C:\Windows\System32
to limit your search and then search in other directories.
var paths = new List<string>
{
Environment.SystemDirectory,
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles)+#"\java",
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)+#"\java",
Environment.GetFolderPath(Environment.SpecialFolder.Programs)+#"\java"
//C:\
//rest
};
foreach (string path in paths)
{
var ser = Search("java.exe", path);
if (!string.IsNullOrEmpty(ser))
{
if (File.Exists(ser))
{
javaExe = ser;
break;
}
}
}
Search function:
private static string Search(string pattern, string root)
{
if (!Directory.Exists(root))
{
return string.Empty;
}
var paths = new Queue<string>();
paths.Enqueue(root);
while (paths.Count > 0)
{
root = paths.Dequeue();
string[] temp = Directory.GetFiles(root, pattern);
foreach (string t in temp)
{
return t;
}
temp = Directory.GetDirectories(root);
foreach (string t in temp)
{
paths.Enqueue(t);
}
}
return string.Empty;
}
Also it's preferred to use this search method to avoid Access permissions.
Note:
You could find java.exe in more than one place.
Do you only want to see if java.exe is there?
File.Exists(#"C:\Program Files\Java\jre7\bin\java.exe")
You might need additional logic to look in the Program Files (x86) folder if needed. Also this will obviously fail if the user installed java somewhere else.
If you want to know where is java, take a look at this other Stack Overflow post.

Recursive search of file/folder structure

I am trying to build a recursive search function for a web service that returns a list of files and folders. I created the two methods so they act as recursive search, it first goes and gets the top level contents, then it adds any files to the fileList, and any sub folders to the subFoldersList. We pass in the access level (in our case root) and then the path which you want the information for. If any folders were found it then removes the top folder because it has begun the search for that folder. Then it calls the processDirectories method, which passes back to getFiles the new path location starting the process all over again. Right now for testing my folder structure is below. When it goes to add the second file (profilepic.png) to the list. I get an error "Collection was modified; enumeration operation may not execute." What is causing this error?
Photos
picture1.png
TestFolder
profilepic.png
my code:
public static List<string> fileList = new List<string>();
public static List<string> subFolderList = new List<string>();
static void processDirectories(string access, string Folder)
{
getFiles(access, Folder);
}
static void getFiles(string access, string Folder)
{
var accessToken = new OAuthToken(token, secret);
var api = new DssAPI(ConsumerKey, ConsumerSecret, accessToken);
var folder = api.GetContents(access, Folder);//Get list from WebService
foreach (var item in folder.Contents)//Contents is an IEnumerable
{
if (item.IsDirectory == true)
subFolderList.Add(item.Path);
else
fileList.Add(item.Path);
}
foreach (var subFolder in subFolderList)
{
subFolderList.RemoveAt(0);
processDirectories(root, subFolder);
}
}
Assuming you're not writing this as an academic exercise, you can use Directory.EnumerateFiles and avoid implementing this yourself.
foreach(var png in Directory.EnumerateFiles(sourceDirectory, "*.png", SearchOption.AllDirectories))
{
// do something with the png file
}
Change that:
foreach (var subFolder in subFolderList)
{
subFolderList.RemoveAt(0);
processDirectories(root, subFolder);
}
To:
while (subFolderList.Count > 0)
{
var subFolder = subFolderList[0];
subFolderList.RemoveAt(0);
processDirectories(root, subFolder);
}
A collection cannot be modified while iterating through it, so when you're foreach-ing it and removing items from it inside the iteration, it causes trouble. The workaround is usually using a for loop and manipulating the loop-variable appropriately, but in your case a while loop is simpler.
the problem is here
foreach (var subFolder in subFolderList)
{
subFolderList.RemoveAt(0);
processDirectories(root, subFolder);
}
You're iterating over subFilderList, and you're removing items from it at the same time. The machine doesn't know how to handle that.
What I would suggest, in this case, is probably doing a regular for-loop
Try this,
Public static void GetFilesLocal( string path)
{
foreach (string f in Directory.GetFiles( path))
{
// Add to subFolderList.
}
foreach (string d in Directory.GetDirectories( path))
{
GetFilesLocal( d );
}
}
You cannot go over the collection and modify it, as the error message says. For example the lower foreach is iterating the subFolderList and then you remove the first item. After that the iterators are not valid.
You should be using for loops, if you want to modify the collections, but then you have to remember to decrease the indexer variable if you delete the first item etc.

Quickest way in C# to find a file in a directory with over 20,000 files

I have a job that runs every night to pull xml files from a directory that has over 20,000 subfolders under the root. Here is what the structure looks like:
rootFolder/someFolder/someSubFolder/xml/myFile.xml
rootFolder/someFolder/someSubFolder1/xml/myFile1.xml
rootFolder/someFolder/someSubFolderN/xml/myFile2.xml
rootFolder/someFolder1
rootFolder/someFolderN
So looking at the above, the structure is always the same - a root folder, then two subfolders, then an xml directory, and then the xml file.
Only the name of the rootFolder and the xml directory are known to me.
The code below traverses through all the directories and is extremely slow. Any recommendations on how I can optimize the search especially if the directory structure is known?
string[] files = Directory.GetFiles(#"\\somenetworkpath\rootFolder", "*.xml", SearchOption.AllDirectories);
Rather than doing GetFiles and doing a brute force search you could most likely use GetDirectories, first to get a list of the "First sub folder", loop through those directories, then repeat the process for the sub folder, looping through them, lastly look for the xml folder, and finally searching for .xml files.
Now, as for performance the speed of this will vary, but searching for directories first, THEN getting to files should help a lot!
Update
Ok, I did a quick bit of testing and you can actually optimize it much further than I thought.
The following code snippet will search a directory structure and find ALL "xml" folders inside the entire directory tree.
string startPath = #"C:\Testing\Testing\bin\Debug";
string[] oDirectories = Directory.GetDirectories(startPath, "xml", SearchOption.AllDirectories);
Console.WriteLine(oDirectories.Length.ToString());
foreach (string oCurrent in oDirectories)
Console.WriteLine(oCurrent);
Console.ReadLine();
If you drop that into a test console app you will see it output the results.
Now, once you have this, just look in each of the found directories for you .xml files.
I created a recursive method GetFolders using a Parallel.ForEach to find all the folders named as the variable yourKeyword
List<string> returnFolders = new List<string>();
object locker = new object();
Parallel.ForEach(subFolders, subFolder =>
{
if (subFolder.ToUpper().EndsWith(yourKeyword))
{
lock (locker)
{
returnFolders.Add(subFolder);
}
}
else
{
lock (locker)
{
returnFolders.AddRange(GetFolders(Directory.GetDirectories(subFolder)));
}
}
});
return returnFolders;
Are there additional directories at the same level as the xml folder? If so, you could probably speed up the search if you do it yourself and eliminate that level from searching.
System.IO.DirectoryInfo root = new System.IO.DirectoryInfo(rootPath);
List<System.IO.FileInfo> xmlFiles=new List<System.IO.FileInfo>();
foreach (System.IO.DirectoryInfo subDir1 in root.GetDirectories())
{
foreach (System.IO.DirectoryInfo subDir2 in subDir1.GetDirectories())
{
System.IO.DirectoryInfo xmlDir = new System.IO.DirectoryInfo(System.IO.Path.Combine(subDir2.FullName, "xml"));
if (xmlDir.Exists)
{
xmlFiles.AddRange(xmlDir.GetFiles("*.xml"));
}
}
}
I can't think of anything faster in C#, but do you have indexing turned on for that file system?
Only way I can see that would make much difference is to change from a brute strength hunt and use some third party or OS indexing routine to speed the return. that way the search is done off line from your app.
But I would also suggest you should look at better ways to structure that data if at all possible.
Use P/Invoke on FindFirstFile/FindNextFile/FindClose and avoid overhead of creating lots of FileInfo instances.
But this will be hard work to get right (you will have to do all the handling of file vs. directory and recursion yourself). So try something simple (Directory.GetFiles(), Directory.GetDirectories()) to start with and get things working. If it is too slow look at alternatives (but always measure, too easy to make it slower).
Depending on your needs and configuration, you could utilize the Windows Search Index: https://msdn.microsoft.com/en-us/library/windows/desktop/bb266517(v=vs.85).aspx
Depending on your configuration this could increase performance greatly.
For file and directory search purpose I would want to offer use multithreading .NET library that possess a wide search opportunities.
All information about library you can find on GitHub: https://github.com/VladPVS/FastSearchLibrary
If you want to download it you can do it here: https://github.com/VladPVS/FastSearchLibrary/releases
If you have any questions please ask them.
Works really fast. Check it yourself!
It is one demonstrative example how you can use it:
class Searcher
{
private static object locker = new object();
private FileSearcher searcher;
List<FileInfo> files;
public Searcher()
{
files = new List<FileInfo>();
}
public void Startsearch()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
searcher = new FileSearcher(#"C:\", (f) =>
{
return Regex.IsMatch(f.Name, #".*[Dd]ragon.*.jpg$");
}, tokenSource);
searcher.FilesFound += (sender, arg) =>
{
lock (locker) // using a lock is obligatorily
{
arg.Files.ForEach((f) =>
{
files.Add(f);
Console.WriteLine($"File location: {f.FullName}, \nCreation.Time: {f.CreationTime}");
});
if (files.Count >= 10)
searcher.StopSearch();
}
};
searcher.SearchCompleted += (sender, arg) =>
{
if (arg.IsCanceled)
Console.WriteLine("Search stopped.");
else
Console.WriteLine("Search completed.");
Console.WriteLine($"Quantity of files: {files.Count}");
};
searcher.StartSearchAsync();
}
}
It's part of other example:
***
List<string> folders = new List<string>
{
#"C:\Users\Public",
#"C:\Windows\System32",
#"D:\Program Files",
#"D:\Program Files (x86)"
}; // list of search directories
List<string> keywords = new List<string> { "word1", "word2", "word3" }; // list of search keywords
FileSearcherMultiple multipleSearcher = new FileSearcherMultiple(folders, (f) =>
{
if (f.CreationTime >= new DateTime(2015, 3, 15) &&
(f.Extension == ".cs" || f.Extension == ".sln"))
foreach (var keyword in keywords)
if (f.Name.Contains(keyword))
return true;
return false;
}, tokenSource, ExecuteHandlers.InCurrentTask, true);
***
Moreover one can use simple static method:
List<FileInfo> files = FileSearcher.GetFilesFast(#"C:\Users", "*.xml");
Note that all methods of this library DO NOT throw UnauthorizedAccessException instead standard .NET search methods.
Furthermore fast methods of this library are performed at least in 2 times faster than simple one-thread recursive algorithm if you use multicore processor.
For those of you who want to search for a single file and you know your root directory then I suggest you keep it simple as possible. This approach worked for me.
private void btnSearch_Click(object sender, EventArgs e)
{
string userinput = txtInput.Text;
string sourceFolder = #"C:\mytestDir\";
string searchWord = txtInput.Text + ".pdf";
string filePresentCK = sourceFolder + searchWord;
if (File.Exists(filePresentCK))
{
pdfViewer1.LoadFromFile(sourceFolder+searchWord);
}
else if(! File.Exists(filePresentCK))
{
MessageBox.Show("Unable to Find file :" + searchWord);
}
txtInput.Clear();
}// end of btnSearch method

Categories