I have a path that looks like the following:
C:\Program Files\AnsysEM\AnsysEm16.0\Win64
I am particularly interested in getting the "16.0" portion of the path. Is there a good way of doing this?
I was thinking of splitting the path, and extracting numbers from the 3rd element in the array. However, I am not sure how robust of a solution this is, or if there is a better way of doing this.
EDIT:
For a little more background, I am getting paths from the registry to determine the location of a couple of exe's. The paths I get are in the form shown above. I need to write these file locations as Environment Variable.
So, if the version is 16.0, I would write something in the registry like: DIR_16_0 with the value of it being the path.
It's a bit hacky, but you can search the string from the regex '\d+.\d+' to match anything of form XXX+.XXX+
var rg = new Regex(#"\d+\.\d+");
var matches = regex.Match(path);
var versionNumber = match.Groups.FirstOrDefault() //eg.
Related
I don't understand the difference between path and directory. Could someone explain to me with examples?
I'm trying to understand how to different classes of system.IO namespace works. But in logicaly I didn't get the mean what is "Path" , what is "Directory". Aren't they both the same thing? Why they divided these 2 thing into two different classes?
Directory is more of a confirmation or assessment of. For example. Does a directory exist providing a string representing the path you are interested in. Create a directory, again, provided a string representing the path.
var myStrPath = #"C:\Users\Public\SomePath\";
if( ! Directory.Exists( myStrPath ))
Directory.Create( myStrPath );
You can also enumerate a given folder looking for more, or cycling through them.
var df = Directory.GetDirectories(#"C:\");
foreach (var oneFolder in df)
MessageBox.Show(oneFolder.ToString());
But you can also use Directory based on RELATIVE Path. For example, where your program is running from, you could do
if( Directory.Exists( "someSubFolderFromWhereRunning" ))
and not worry about fully qualified path.
Path allows you to get or manipulate path/file information, such as a relative path above and you want to know its FULL path even though you dont know where your program is running from. This might be good to look for an expected startup check file in the relative directory the app is running from, or writing files out to same working folder.
You can also get the list of bad characters that are not allowed in a path so you can validate against them in some string.
For each of them, take a look at the "." reference after you do something like
var what = System.IO.Directory. [and look at the intellisense]
var what2 = System.IO.Path. [intellisense]
And look at the context. It should make more sense to you seeing it with better context.
A Directory is a disk file that contains reference information to other files. or in simple words, it is a folder.
A Path is just a string wrapped in a Path Class in C# which facilitates us with many different conventions depending on the operation system.
I am developing a program that functions similar to the MS-DOS command "cd". The user types "cd.." into the program's prompt and then, using Stringbuilder, remove the characters representing the user's current directory. It would function like this:
Prompt> cd..
with a Stringbuilder instance declared in the code file:
Stringbuilder builder = new Stringbuilder(#"E:\Folder");
After the user types "cd.." and hits Enter, the program would remove the directory at the end of the Stringbuilder value, with the end result like this:
Stringbuilder builder = new Stringbuilder(#"E:\");
I am not sure how I can do this, or if it is even possible to do. I thought I could try builder.Length - Directory.Length to get the length of the directory name, and then use builder.Remove(int StartIndex, int length), but I don't know how that could be implemented.
Another thing I could possibly use is using builder.ToString() and split it, using the backslash as the seperator.
Any suggestions?
You could use Path.GetDirectoryName, but it's kind of dumb. It just does string manipulation with no idea what the file system actually looks like. For example, if you do Path.GetDirectoryName(#"E:\Folder\") it will return "E:\Folder", because there was a slash at the end of the string you gave it. Or you could feed it a folder that doesn't even exist, and it'll still give you an answer.
I can suggest another way to do this: keep a DirectoryInfo object for the current working directory. For example:
var curDirectory = new DirectoryInfo(#"E:\Folder");
When you need to display it, use curDirecotry.FullName, which will return the full path, like "E:\Folder". Then when you need to go up a directory, it's one line with no string manipulation:
curDirectory = curDirectory.Parent;
Although you do have to check it for null since, if you are already at the root of the drive, Parent will be null.
DirectoryInfo actually looks at the file system so you can be sure that it's always valid. Plus, you can use it for seeing the contents of the folder too, which I'm sure you will want to do.
We ran into the same kind of behaviour exhibited by this post:
Why does Path.Combine produce this result with a relative path?
Where:
var basePath = #"\\server\BaseFolder";
var relativePath = #"\My\Relative\Folder";
var combinedPath = Path.Combine(basePath, relativePath);
produces an output of \My\Relative\Folder instead of the expected \\server\BaseFolder\My\Relative\Folder.
After reading this and other posts, as well as the MSDN doc:
If the one of the subsequent paths is an absolute path, then the
combine operation resets starting with that absolute path, discarding
all previous combined paths.
I understand this behaviour exactly, as well as what it's doing and how to fix it.
What I don't understand is why!
In what scenarios would this be the required behavior? Why would you ever want to pass in a set of arguments here, and have it completely ignore whatever first few you pass in and just take the last few instead?
Surely this would be better treated by Microsoft as an exception rather than just ignoring the parameters - if an absolute path is tried to be merged with a path which was already absolute surely that's an invalid argument...
Probably going to write my own method to do what I want, just wanted to get everyone's opinion on why it could have been purposely designed like this.
Simple. Your relativePath is not actually a relative path.
The correct path must not start with a \ - that roots it. If you use My\Relative\Folder, it will work as you expect it to.
In fact, you'll see this kind of behaviour in many places, including the windows command processor. If I am in C:\Windows, what will dir \ print out?
I use this code for finding the debug directory
public string str_directory = Environment.CurrentDirectory.ToString();
"C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj\\bin\\Debug"
How can I find the parent folder as shown below?
"C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj"
You can use System.IO.Directory.GetParent() to retrieve the parent directory of a given directory.
string parent = System.IO.Directory.GetParent(str_directory).FullName;
See BOL
If you append ..\.. to your existing path, the operating system will correctly browse the grand-parent folder.
That should do the job:
System.IO.Path.Combine("C:\\Users\\Masoud\\Documents\\Visual Studio 2008\\Projects\\MyProj\\MyProj\\bin\\Debug", #"..\..");
If you browse that path, you will browse the grand-parent directory.
Edit: The normalization covered in this answer only happens when the path is used to access the file system, but not on the string itself. By contrast, this answer achieves the result and normalization purely using path strings, without using the file system at all.
I've found variants of System.IO.Path.Combine(myPath, "..") to be the easiest and most reliable. Even more so if what northben says is true, that GetParent requires an extra call if there is a trailing slash. That, to me, is unreliable.
Path.Combine makes sure you never go wrong with slashes.
.. behaves exactly like it does everywhere else in Windows. You can add any number of \.. to a path in cmd or explorer and it will behave exactly as I describe below.
Some basic .. behavior:
If there is a file name, .. will chop that off:
Path.Combine(#"D:\Grandparent\Parent\Child.txt", "..") => D:\Grandparent\Parent\
If the path is a directory, .. will move up a level:
Path.Combine(#"D:\Grandparent\Parent\", "..") => D:\Grandparent\
..\.. follows the same rules, twice in a row:
Path.Combine(#"D:\Grandparent\Parent\Child.txt", #"..\..") => D:\Grandparent\
Path.Combine(#"D:\Grandparent\Parent\", #"..\..") => D:\
And this has the exact same effect:
Path.Combine(#"D:\Grandparent\Parent\Child.txt", "..", "..") => D:\Grandparent\
Path.Combine(#"D:\Grandparent\Parent\", "..", "..") => D:\
To get a 'grandparent' directory, call Directory.GetParent() twice:
var gparent = Directory.GetParent(Directory.GetParent(str_directory).ToString());
Directory.GetParent is probably a better answer, but for completeness there's a different method that takes string and returns string: Path.GetDirectoryName.
string parent = System.IO.Path.GetDirectoryName(str_directory);
Like this:
System.IO.DirectoryInfo myDirectory = new DirectoryInfo(Environment.CurrentDirectory);
string parentDirectory = myDirectory.Parent.FullName;
Good luck!
No one has provided a solution that would work cross-form. I know it wasn't specifically asked but I am working in a linux environment where most of the solutions (as at the time I post this) would provide an error.
Hardcoding path separators (as well as other things) will give an error in anything but Windows systems.
In my original solution I used:
char filesep = Path.DirectorySeparatorChar;
string datapath = $"..{filesep}..{filesep}";
However after seeing some of the answers here I adjusted it to be:
string datapath = Directory.GetParent(Directory.GetParent(Directory.GetCurrentDirectory()).FullName).FullName;
You might want to look into the DirectoryInfo.Parent property.
IO.Path.GetFullPath(#"..\..")
If you clear the "bin\Debug\" in the Project properties -> Build -> Output path, then you can just use AppDomain.CurrentDomain.BaseDirectory
Since nothing else I have found helps to solve this in a truly normalized way, here is another answer.
Note that some answers to similar questions try to use the Uri type, but that struggles with trailing slashes vs. no trailing slashes too.
My other answer on this page works for operations that put the file system to work, but if we want to have the resolved path right now (such as for comparison reasons), without going through the file system, C:/Temp/.. and C:/ would be considered different. Without going through the file system, navigating in that manner does not provide us with a normalized, properly comparable path.
What can we do?
We will build on the following discovery:
Path.GetDirectoryName(path + "/") ?? "" will reliably give us a directory path without a trailing slash.
Adding a slash (as string, not as char) will treat a null path the same as it treats "".
GetDirectoryName will refrain from discarding the last path component thanks to the added slash.
GetDirectoryName will normalize slashes and navigational dots.
This includes the removal of any trailing slashes.
This includes collapsing .. by navigating up.
GetDirectoryName will return null for an empty path, which we coalesce to "".
How do we use this?
First, normalize the input path:
dirPath = Path.GetDirectoryName(dirPath + "/") ?? ""; // To handle nulls, we append "/" rather than '/'
Then, we can get the parent directory, and we can repeat this operation any number of times to navigate further up:
// This is reliable if path results from this or the previous operation
path = Path.GetDirectoryName(path);
Note that we have never touched the file system. No part of the path needs to exist, as it would if we had used DirectoryInfo.
To avoid issues with trailing \, call it this way:
string ParentFolder = Directory.GetParent( folder.Trim('\\')).FullName;
To get your solution
try this
string directory = System.IO.Directory.GetParent(System.IO.Directory.GetParent(Environment.CurrentDirectory).ToString()).ToString();
This is the most common way -- it really depends on what you are doing exactly:
(To explain, the example below will remove the last 10 characters which is what you asked for, however if there are some business rules that are driving your need to find a specific location you should use those to retrieve the directory location, not find the location of something else and modify it.)
// remove last 10 characters from a string
str_directory = str_directory.Substring(0,str_directory.Length-10);
You shouldn't try to do that. Environment.CurrentDirectory gives you the path of the executable directory. This is consistent regardless of where the .exe file is. You shouldn't try to access a file that is assumed to be in a backwards relative location
I would suggest you move whatever resource you want to access into a local location. Of a system directory (such as AppData)
In my case I am using .NET 6. When I use:
public string str_directory = Environment.CurrentDirectory.ToString();
returns C:\Projects\MyTestProject\bin\Debug\net6.0
In order to reach C:\Projects\MyTestProject I am using the following:
Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent
You can chain Parent to Directory.GetParent(Environment.CurrentDirectory) in order to reach the directory you want.
Final version:
public string str_directory = Directory.GetParent(Environment.CurrentDirectory).Parent.Parent.ToString();
In C#, is there any built-in way to "correct" URLs that have parent pathing in them? So, I want to take this:
/foo/bar/../baz.html
And turn it into...
/foo/baz.html
(The "bar" directory being negated by the ".." after it in the path.)
I've tried to hand-roll this, but the logic gets pretty ugly, pretty quickly. Consider something like:
/foo1/foo2/../foo3/foo4/foo5/../../bar.html
The path I headed down was to move through the URL, segment by segment, and start writing a new URL. I would only include segment 1 in the new URL, if segment 2 wasn't "..". But, in the case above, I need to "look ahead" and figure out how many parent paths I have coming.
I tried to use Path.GetFullPath, and it technically got it work, but, man, it's ugly. Fair warning: you may want to avert your eyes on this one:
Path.GetFullPath(myUrl).Replace(Path.GetFullPath(#"\"), "").Replace(#"\", "/") + "/";
GetFullPath returns a file system path from the "C:\" root, so you essentially have to replace that too, than convert the slashes, etc.
I can probably bang this out eventually (and my ugly code above technically works), but it strikes me that I can't be the first one to try this. Google did not help.
(The answer in another language would be helpful too -- at least it would show the logic.)
This should work for all URLs (including URLs with a QueryString):
var url = "/foo/bar/../bar.html";
var ubuilder = new UriBuilder();
ubuilder.Path = url;
var newURL = ubuilder.Uri.LocalPath;
Try the VirtualPathUtility class. It has some methods that should be able to help here, specifically the ToAbsolute() method, which if memory doesn't fail me, should be able to take an application-relative path and convert it to an application absolute path.
If you really want to roll your own version, try using a stack:
split path by path separator '/'
loop through segments
push any segment that is not '..' onto a stack
if the segment is '..', pop the stack
join the segments with the path separator '/'
But as others have noted: It is probably better to get your library to do this for you.