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.
Related
I d like to create a blind test generator with a script using Sony vegas 14. For this I must make my script in C#.
I don’t have many experiences in C# so maybe my problem is a very basic one.
To do my script I must use a library class (.dll) and execute my script by Sony vegas. To test my code easily I create a console app where I try my code and can easily print in the console what my code does.
For my program y need to get the path of all subdirectory in a Directory in a string.
My problem is the next one.
the command "Directory.GetDirectories" don't work
When I use the next code to check what in my array/list I get a coherent result if I use it in the console app version on my script (the number of subdirectories in my directory)
string[] dirs = Directory.GetDirectories(myDirectorypath, "", SearchOption.TopDirectoryOnly);// get all directory path in dirs
Console.WriteLine("the number of element in your array is "+ dirs.Length);
List<string> listdedossier = new List<string>(dirs); // convert the array in a list
Console.WriteLine("the number of element in your list is " + listdedossier.Count);
But when in paste my code in my dll project nothing is written in my array or my list. I notice this because when I want to print the number of elements in the list /array that return me 0
.
do you have any idea of what happen i my code?
thanks
You should check the online Microsoft documentation for GetDirectories. The 2nd argument is supposed to be a pattern to search for that conforms to Windows file name patterns. Essentially, all or part of a file name is allowed with * being a wildcard (The .* from regex meaning "match any character any number of times") and ? being a single character wildcard (regex .). You are providing an empty string, so you get nothing back. The pattern *.exe will match all executables in a folder (if you are using GetFiles, while the pattern pattern* matches any files/folders that start with pattern. If you want all directories, do this:
string[] dirs = Directory.GetDirectories(myDirectoryPath, "*", SearchOption.TopDirectoryOnly);
Next point, the path you provide can be either a relative path (e.g., "relative\path\to\folder"), an absolute path (e.g., "D:\path\to\folder"), or a fully qualified domain name (FQDN, e.g. "\servername.gov.edu.com\drive$\path\to\folder"). If you supply a relative path, you'll need to look up Windows' rules for path resolution. It is very easy using a relative path to search the wrong folder, or even a non-existent location (though you should get an exception in that case). Also remember: Windows path names are NOT case-sensitive.
Finally, when writing text with arguments, I HIGHLY recommend you use this format:
Console.WriteLine("The number of elements in your array is {0}", dirs.Length);
This uses a place holder in the string itself which has a numeric value in it. The number indicates what argument after the format string to use (0 is the first argument after the format string). You can use as many placeholders as you want, and use the same place holder in multiple locations. This is a more type-safe way to doing string printing in C# than using the + operator, which requires that an operator be defined that takes a string and whatever type you provided. When you use placeholders, WriteLine will use the built-in ToString method which is defined for all types in the Object class. Placeholders will always work, while using + will only sometimes work.
I want to create a data file, but before writing to the final file I want to drop it in a temporary location to avoid user confussion. As an example, I could begin with test.txt and want to have test.txt.tmp. The names could include a path, but the files may not necesarily exist (so this question is purely about string manipulation).
The closest I have been is to use Path.ChangeExtension:
string original = "test.txt";
string temp = Path.ChangeExtension(original, "tmp");
But that returns test.tmp instead. So my question is if there is a built-in method to achieve that "dual-extension" file name? I could always use brain-dead string concatenation, but I'm looking for a more safe and tested method.
Avoiding pitfalls is a great idea for things like Path.Combine, e.g. because you don't want to be bothered checking if there is no missing \ character.
But there are no pitfalls here.
If your original filename is as you expect it to be, then string concatenation will work.
If your original file name is not as you expect it to be, then the issue lies with whoever supplied you a faulty filename. "Shit goes in, shit comes out" is not really something your internal logic should worry about. An algorithm can only be as correct as the information that it receives.
String concatenation is perfectly acceptable here. There is no premade method here because there is no real pitfall to simply concatenating the strings.
Special shout out to AlessandroD'Andria's suggestion:
Path.ChangeExtension(original, Path.GetExtension(original) + ".tmp");
Technically, it employs Path logic and therefore fits with your criteria. I genuinely like the cleverness of following your expectations.
However, there is simply no merit to doing so. By its very nature an extension is defined as being "the last part of the filename".
Whether you do a direct string concatenation, or instead do this:
chop the string into two pieces (filename, extension)
append something to the last piece (extension + temp extension)
paste everything together again
The end result will always be the same. The chopping of the string is unnecessary work.
Why can't you append that string just like
if(!string.IsNullOrEmpty(Path.GetExtension(original)){
original+= ".tmp";
}
You should use temp file and rename the extension.
string path = Path.GetTempFileName();
// some logic on the file then rename the file and move it when you need it
string fileName = Path.GetFileName(path);
File.Move(path, path.Replace(fileName, "test.txt"));
If you would use temp file, you can use Path.GetTempFileName();
string tempFileName = Path.GetTempFileName();
Or in your case:
string original = "test.txt";
string temp = "test.txt" + ".tmp";
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.
Running this snippet
var path1 = #"C:\Temp\SomeFolder";
var path2 = #"C:\Temp\SomeFolder\";
Console.WriteLine(Directory.GetParent(path1));
Console.WriteLine(Directory.GetParent(path2));
Output
C:\Temp
C:\Temp\SomeFolder
Same story with Path.GetDirectoryName(), which also can be used to obtain parent folder, but will similarly fail in case of \ at the end.
I do really like Path.Combine() for ignoring slashes at the end and do really hate some guys who make some methods returning path with slash (referring to AppDomain.CurrentDomain.BaseDirectory *angryface*).
Question: how to properly handle possible slash at the end of given path when I need to get one of the parent directories?
Here is another snippet
var path1 = #"C:\Temp\SomeFolder";
var path2 = #"C:\Temp\SomeFolder\";
var dir1 = #"Test";
var dir2 = #"Test\";
Console.WriteLine(Path.Combine(path1, dir1));
Console.WriteLine(Path.Combine(path1, dir2));
Console.WriteLine(Path.Combine(path2, dir1));
Console.WriteLine(Path.Combine(path2, dir2));
Output
C:\Temp\SomeFolder\Test
C:\Temp\SomeFolder\Test\
C:\Temp\SomeFolder\Test
C:\Temp\SomeFolder\Test\
Path.Combine works properly (ignoring ending slash of the first path, or well, adding it when it's missing), while persisting ending slash of second path (for whatever reasons, I do not care, because using resulting path in more Path.Combines will works as well).
As I understand Test and Test\ pointing at the same folder in directory structure. And if I want to get parent (previous folder), then Directory.GetParent should return me previous folder, and not Test folder again.
Question: how to properly handle possible slash at the end of given
path when I need get one of the parent directories?
Just trim it from the input string. Use TrimEnd:
Console.WriteLine(Directory.GetParent(path1.TrimEnd('\\')));
However returning the complete path when the string is terminated by \ is desired behaviour
Directory.GetParent Method
However, passing "C:\Directory\SubDirectory\" returns
"C:\Directory\SubDirectory", because the ending directory separator is
after "SubDirectory".
Some Path theory:
A file system contains Containers (Folders, Directories) and Elements (Files).
A "Path" Contains a set of (hierarchical) Containers and probably an "Element" as last element, all separated by slashes.
In theory, if the "Element" is missing, there is a trailing slash to indicate that the last item is a Container:
/Directory/Subdirectory/
And a Path without trailing slash points to an "Element", not an "Container"
/Directory/Subdirectory/Element
This is the theoretically clean way to handle things. Because it is often too cumbersome for end-users to deal with clean theory, the software often tolerates a missing trailing slash after a final "Container":
/Directory/Subdirectory
This is just a "hack" to make the life of the end-user easier and basically agiuants the theoretically sound specs for pathes.
Edit
This convention has its drawbacks and introduces missbehaviour at different places.
Look at the Directory.GetParent() method. It accepts a string and works with string manipulations only. So this method can not decide if the last item is a "Container" or an "Element" if the trailing slash is missing. It assumes to see an "Element" as last element and returns the next "Container". If the last item happens to be a "Container" (and we mean "all content in this container") this is indeed the wrong answer.
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();