Creating a file system path branch in C# - c#

I have what I think is probably quite a simple question to answer (for someone). Given a path, say C:\A\B\C\D\, what is the most efficient, compact and elegant way to re-create that path on the system, assuming it doesn't already exist (C:\A\B might, of course), in c#?
The only thing I can think of involves a rather grubby looking little path parser, with all of the potential pit-falls this entails. I'm sure many people here will have encountered this little problem before and have a better solution than I can come up with.
So, your thoughts please gentlemen (and ladies)?

System.IO.Directory.CreateDirectory(#"C:\A\B\C\D\") will do just fine.

MSDN example
// Specify the directories you want to manipulate.
DirectoryInfo di = new DirectoryInfo(#"c:\MyDir");
try
{
// Determine whether the directory exists.
if (di.Exists)
{
// Indicate that it already exists.
Console.WriteLine("That path exists already.");
return;
}
// Try to create the directory.
di.Create();
Console.WriteLine("The directory was created successfully.");
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
finally {}

Directory.CreateDirectory(#"C:\A\B\C\D\");
Creates all directories in the path if they don't already exist, and even returns you a DirectoryInfo object of the child directory (D, in this case).

You might want to have a look into MSDN and the ´Directory.exists´-Method.
This way you can detect if "C:\A\B\C\D..." already exists and if not you can create it with Directory.Create(String directoryName)...

Directory.CreateDirectory will take care of that for you.

string folderPath = "C:\A\B\C\D"
if (!System.IO.Directory.Exists(folderPath))
System.IO.Directory.CreateDirectory(folderPath);

Related

Removing a directory with files inside AppData

Well, what I want to do is to remove my folder that is located inside Roaming. I want this to work for every user, so the username of every PC is different. I already know that to get path of AppData I need following:
var path = Environment.SpecialFolder.ApplicationData;
But what to do to remove the folder with a specific name (Let's call it ExampleDir)? I tried this:
Path.Combine(path + "Kappa");
Directory.Delete(true.ToString());
But this does not work. I am beginner at C#, still, I want to practice. Will be grateful for help =)
First of all, Path.Combine() is used to replace string concatenation so don't concatenate strings in it. Pass every name you want to concatenate as a parameter and the function will do the rest.
Secondly, to remove a folder containing files you have to use the Directory.Delete(string, bool) overload. The bool value (called recursive) indicates wether you want to remove files and subfolders in the specified directory (see the MSDN Documentation for Directory.Delete()).
And finally, Environment.SpecialFolder.ApplicationData is just an enumration (meaning it's just a number). You have to pass it as a parameter to the Environment.GetFolderPath() method to get the actual path of the AppData folder.
Example:
string AppDataFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string FolderToDelete = Path.Combine(AppDataFolder, "Kappa");
try
{
Directory.Delete(FolderToDelete, true); //Setting "recursive" to true will remove every subfile/-folder.
}
catch (Exception ex)
{
//An error occurred, use this block to log it/show it to the user/whatever.
//ex.Message - The error message.
//ex.StackTrace - Where in the code the error occurred.
}
EDIT:
As #dman2306 said in his comment, some exception handling is good practice in case of that the deletion fails. I have added this to my above code.
The code in the try block will run until an exception is thrown (if any). If an exception is thrown the execution will move on to the catch block, which is where you catch the exception and perform for example error logging, stopping other procedures, etc.
EDIT 2:
You possibly have to add "Roaming" to Path.Combine(). I am unsure if it's already included or not, and I'm unable to test that now.
string FolderToDelete = Path.Combine(AppDataFolder, "Roaming", "Kappa");
Forget what I said, SpecialFolder.ApplicationData gives you the path to the Roaming folder.
First of all you are using Path.Combine() wrong. But you don't need that at all.
Second you have to use backslases to separate folders in a path when combining them with +.
And third: The method Directory.Delete() wants the path of the folder you want to delete as an argument.
Try this:
Directory.Delete(Environment.SpecialFolder.ApplicationData + "\\Kappa");

Get rights on folder

I'm trying to get right for a folder. The purpose is to create a file inside this folder when i ask my program to create this file. I tried almost everything and it still don't work.
try
{
DirectorySecurity ds = Directory.GetAccessControl(path);
foreach (FileSystemAccessRule rule in ds.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)))
{
if ((rule.FileSystemRights & FileSystemRights.CreateFiles) > 0 /*== FileSystemRights.CreateFiles)*/)
return true;
}
}
catch (UnauthorizedAccessException e)
{
return false;
}
return false;
My problem is: The FileSystemAccessRule said that I have the permissions but when I want to create my file, "unauthorizedexception" exception appears.
I tried to use a DirectoryInfo, like that:
DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity ds = di.GetAccessControl();
instead of to use the "Directory" object directly. Plus, i was thinking that my problem was concerning the GetAccessRules, so I tried to use the SecurityIdentifier and also NTAccount, both said that I have all the right on this folder (FullControl) whereas at the end, i don't have any right. And of course my path is good, I checked it.
Someone knows another method to get the right on a folder, or if I do something wrong, a bit of help will be a pleasure.
I think the problem with your code is that is does not check on the specific users which have access. GetAccessControl gets a list of ALL users that have any access rule applied to the folder, not just YOU.
There is an excellent answer already here how to do the proper checking: Checking for directory and file write permissions in .NET

Why does System.IO.File.Exists(string path) return false?

System.IO.File.Exists(string path)
returns always false, even when the file exists on the specified path. What could be the possible solution?
It could well be a permission problem. From the documentation:
The Exists method returns false if any error occurs while trying to determine if the specified file exists. This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters, a failing or missing disk, or if the caller does not have permission to read the file.
One way of seeing what's happening is to just try to read the file (e.g. with File.OpenRead). I'd be surprised if that succeeds - but if it fails, the exception should give you more information.
Hiding file endings in windows can sometimes cause confusion: you KNOW your file is named file.txt when it is actually named file.txt.txt because the last 4 characters have been hidden by the OS.
One possibility not mentioned in any of the answers here is 'File System Redirection' on Windows 8.1 onward.
For example, if your program is a 32-bit application and you're running on 64-bit Windows then an attempt to access %windir%\System32 would be redirected to %windir%\SysWOW64. And if the file you're trying to access doesn't exist in %windir%\SysWOW64 then System.IO.File.Exists(string path) would return False.
Link to a nice article explaining this behavior
I was puzzling over this as well, then realized I was using File.Exists when I should have been using Directory.Exists.
in my case, a different "dash" in file name causes the issue.
var f1 = "4-37R.pdf";
var f2 = "4‐37R.pdf";
var r = f1==f2?"same":"diff";
Console.Write(r); //diff
turns out
var c1 = '-';
var c2 = '‐';
Console.WriteLine((int)c1); //45
Console.WriteLine((int)c2); //8208
use the same '-' fixes the issue.
How I got around this was using Server.MapPath(fileName) as it kept trying to find the file somewhere else.
System.IO.File.Exists(Server.MapPath(string path))
This had me stumped for a while while I was debugging a service locally, I was running File.Exists("U:\dir1") against a server location mapped on my workstation as (U:). I replaced the U:\dir1 to "\\serverPath\dir1" and File.Exists then returned true.
I was experiencing this myself too. In my case, I was deleting the file and re-creating it. In the process that was deleting the file, I forgot to add in WaitForExit() before using File.Exists later on
I just learned today that System.IO.File.Exists will return false if the file exists but is empty
System.IO.File.Exists(string path) returned false for me while trying to read C:\OpenSSL\bin\file.txt.
Running the application in Administrator mode did not help.
(I was logged on the administrator account, Windows 10)
Once I moved the file to C:\Users\MyUser\Desktop\file.txt, File.Exists() returned true.
Here's one more, which took me far too long to twig to.
The file name was in a constructed variable that was use to write the file, then the same variable used to check that it had been successfully written, so it could not have been different versions of '-'. I am running mono on Linux and debugging as a different user than the program is normally run by/as. Many of these types of errors are related to permissions and I spent a while banging my head on that. When File.OpenRead also threw "file not found" I finally noticed my file name had a space character at the end. I only saw this when I copied the exception message, which showed quote marks around the file name string, revealing the included space.
Apparently you can write a file name with a trailing space, but File.Exists trims that off and doesn't recognize it. When I eliminated the trailing space File.Exists worked as expected.
There can be requirement to use the DirectoryProvider Refresh() process to get the correct result from the Exists function.
e.g. code as per:
private DirectoryInfo CreateDirectory(string folderPath, int code, string message)
{
DirectoryInfo di;
try
{
di = DirectoryProvider.CreateDirectory(folderPath);
}
catch
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
di.Refresh();
if (!DirectoryProvider.Exists(di))
{
throw new WebServiceException(code, HttpStatusCode.BadRequest, message);
}
return di;
}
I was using System.IO.Path.Combine and assuming it would remove any trailing white space. For the life of me I could figure out why System.IO.File.Exists(path) was returning false.
I used the below snippet to test why it was failing
Turns out that a trailing white space was introduced causing an
"The filename, directory name, or volume label syntax is incorrect inside batch"
Hopefully someone will avoid the same stupid mistake as me
bool FileExists(string path){
try
{
using var stream = File.Open(path, FileMode.Open);
return true;
}
catch (FileNotFoundException)
{
return false;
}
catch (DirectoryNotFoundException)
{
return false;
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine(ex.message);
throw;
}
catch (Exception ex)
{
Console.WriteLine(ex.message);
throw;
}
}

How to get the exact path of notepad.exe in order to associate a file extension

I need to associate a file extension I have created “.rulog” with notepad.exe as part of a setup project installation for a windows 7 machine (it’s here since we require admin privileges to write to the registry).
Basically I need to obtain programmatically the exact path of the notepad.exe. Now, I understand that it typically lives in C:\Windows\system32. This is part of PATH system environment variable, so I guess I could loop through all the PATH variables and test if “notepad.exe” exists by combining “notepad.exe” with the current path using File.Exists. However this feels very clumsy.
Essentially I need to add an entry to
Computer\HKEY_CLASSES_ROOT\.rulog\shell\open\command\
with the value of the path of notepad.
Incidentally I can see that .txt in:
Computer\HKEY_CLASSES_ROOT\.txt\ShellNew
has a value for ItemName of
“#%SystemRoot%\system32\notepad.exe,-470”
Perhaps I can just copy this value? Or is this dangerous?(e.g. does not exist).
You can use:
Environment.GetEnvironmentVariable("windir") + "\\system32\\notepad.exe";
Or even easier:
Environment.SystemDirectory + "\\notepad.exe";
That way it doesn't matter which drive the os is on.
Copying the value with %systemroot% should be just fine. If it works for the OS, it should work for you!
Fool-proof solution:
string NotepadPath = Environment.SystemDirectory + "\\notepad.exe";
if (System.IO.File.Exists(NotepadPath))
{
Microsoft.Win32.Registry.SetValue("HKEY_CLASSES_ROOT\\.rulog\\shell\\open\\command\\", "", NotepadPath + " %1");
}
else
{
//do something else or throw new ApplicationException("Notepad not found!");
}

C# Search for subdirectory (not for files)

Every example I see seems to be for recursively getting files in subdirectories uses files only. What I'm trying to do is search a folder for a particular subdirectory named "xxx" then save that path to a variable so I can use it for other things.
Is this possible without looping through all the directories and comparing by name?
Well
Directory.GetDirectories(root);
will return you an array of the subdirectories.
You can then use Linq to find the one you're interested in:
IEnumerable<string> list = Directory.GetDirectories(root).Where(s => s.Equals("test"));
which isn't a loop in your code, but is still a loop nevertheless. So the ultimate answer is that "no you can't find a folder 'test' without looping".
You could add .SingleOrDefault() to the Linq, but that would depend on what you wanted to do if your "test" folder couldn't be found.
If you change the GetDirectories call to include the SearchOption SearchOption.AllDirectories then it will do the recursion for you as well. This version supports searching - you have to supply a search string - though in .NET Framework it's case sensitive searching. To return all sub directories you pass "*" as the search term.
Obviously in this case the call could return more than one item if there was more than one folder named "test" in your directory tree.
var foldersFound = Directory.GetDirectories(root, "test", SearchOption.AllDirectories)
This will return a string array with all the folders found with the given name. You can change the last parameter so that it only checks top level directories and you can change root to adjust where it is starting from.
First of all, "No, it is not possible without looping through all the directories and comparing by name".
I believe your real question is "Is there an existing API which will handle looping through all the directories and comparing by name for me?"
Yes, there is. It's called Directory.Exists():
var xxxPath = Path.Combine(parentFolder, "xxx");
if (Directory.Exists(xxxPath))
savedPath = xxxPath;
Yes, I believe that the only available solution (short of third party libraries) is a recursive search for the directory via name comparison.
You can use Windows Search which provides api for .Net too. Here is more detailed information: Windows Search 4.0 for Developers
Here is a snippet for searching for a folder using two filters while considering for the UnauthorizedAccessException, it can be refactored to use only one filter:
public static string FindGitPath(string firstFilter, string secondFilter, string initialPath)
{
string gitPath = string.Empty;
foreach (var i in Directory.GetDirectories(initialPath)) {
try {
foreach (var f in Directory.GetDirectories(i, firstFilter, SearchOption.AllDirectories)) {
foreach (var s in Directory.GetDirectories(f)) {
if (s == Path.Combine(f,secondFilter)) {
gitPath = f;
break;
}
}
}
} catch (UnauthorizedAccessException) {
Console.WriteLine("Path is not accessible: {0}", i);
}
}
return gitPath;
}
Usage example:
Console.WriteLine("Retrieved the git database folder as {0}", FindGitPath("database",".git", "c:\\"));

Categories