Given a file is in C drive, and its path ends with "Framework64\v4.0.30319\WPF\Fonts\GlobalMonospace.CompositeFont", what is the most efficient way to find the file?
It may be able to find, for example, "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\Fonts\GlobalMonospace.CompositeFont".
I can implement it in C# or AutoHotKey. I think Directory.EnumerateFiles and loop directive will work, but what is the most efficient way?
Use Directory.EnumerateDirectories with option SearchOption.AllDirectories to find all directories. Then pick those whose path ends in "Framework64\v4.0.30319\WPF\Fonts". Then for those, check whether the file "GlobalMonospace.CompositeFont" exists in those directories using File.Exists.
Loop, C:\*Framework64\v4.0.30319\WPF\Fonts\GlobalMonospace.CompositeFont, , 1 ; recurse into subfolders
{
MsgBox, 4, , Filename = %A_LoopFileFullPath%
continue?
IfMsgBox, No
break
}
https://autohotkey.com/docs/commands/LoopFile.htm
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 have a directory with multiple sub directories that contain .doc files. Example:
C:\Users\user\Documents\testenviroment\Released\test0.doc
C:\Users\user\Documents\testenviroment\Debug\test1.doc
C:\Users\user\Documents1\testenviroment\Debug\test2.doc
C:\Users\user\Documents1\testenviroment\Released\test20.doc
I want to get all the test*.doc files under all Debug folders. I tried:
string[] files = Directory.GetFiles(#"C:\Users\user", "*Debug\\test*.doc",
SearchOption.AllDirectories);
And it gives me an "Illegal characters in path" error.
If I try:
string[] files = Directory.GetFiles(#"C:\Users\user", "\\Debug\\test*.doc",
SearchOption.AllDirectories);
I get a different error: "Could not find a part of the path C:\Users\user\Debug".
You are including a folder within the search pattern which isn't expected. According to the docs:
searchPattern Type: System.String The search string to match against
the names of files in path. This parameter can contain a combination
of valid literal path and wildcard (* and ?) characters (see Remarks),
but doesn't support regular expressions.
With this in mind, try something like this:
String[] files = Directory.GetFiles(#"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
.Where(file => file.Contains("\\Debug\\"))
.ToArray();
This will get ALL the files in your specified directory and return the ones with Debug in the path. With this in mind, try and keep the search directory narrowed down as much as possible.
Note:
My original answer included EnumerateFiles which would work like this (making sure to pass the search option (thanks #CodeCaster)):
String[] files = Directory.EnumerateFiles(#"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
.Where(file => file.Contains("\\Debug\\"))
.ToArray();
I've just run a test and the second seems to be slower however it might be quicker on a larger folder. Worth keeping in mind.
Edit: Note from #pinkfloydx33
I've actually had that practically take down a system that I had
inherited. It was taking so much time trying to return the array and
killing the memory footprint as well. Problem was diverted converting
over to the enumerable counterparts
So using the second option would be safer for larger directories.
The second parameter, the search pattern, works only for filenames. So you'll need to iterate the directories you want to search, then call Directory.GetFiles(directory, "test*.doc") on each directory.
How to write that code depends on how robust you want it to be and what assumptions you want to make (e.g. "all Debug directories are always two levels into the user's directory" versus "the Debug directory can be at any level into the user's directory").
See How to recursively list all the files in a directory in C#?.
Alternatively, if you want to search all subdirectories and then discard files that don't match your preferences, see Searching for file in directories recursively:
var files = Directory.GetFiles(#"C:\Users\user", "test*.doc", SearchOption.AllDirectories)
.Where(f => f.IndexOf(#"\debug", StringComparison.OrdinalIgnoreCase) >= 0);
But note that this may be bad for performance, as it'll scan irrelevant directories.
I have to come back 5 folders in path then I need to enter 3 folders further and check if file exist.
Lets imagine two paths:
1) C:\a\b\c\d\e\f\g\
2) C:\a\2\3\4\5\test.xml
Then my program right now is on the first path.
I need to check if file test.xml (on the second path) exists.
For that I know method File.Exists(path), however I have problems with path.
I am able to come back until folder a and check if the file is there.
For example to check if the file on the path exists:
3) C:\a\test2.xml
I may use:
File.Exists(#".\.\.\.\.\.\" + #"test2.xml");
But nevertheless my attempts to navigate to second path ( 2) ) and check if this file exists I can not to that. May anyone help me with that ? Thanks in advance. Regards.
. refers to the current directory
.. refers to the directory one level above the current
In your example:
..\..\..\..\..\..\2\3\4\5\test.xml
This moves up to the a directory then traverses down to 5 where your file resides.
Something that might be helpful to test your path and ensure you are where you think you are is this:
string currentPath = Path.GetFullPath(relativePath);
And then check the value of currentPath, if it winds up somewhere you didn't expect you can debug your path traversal rather than your code.
You just need to use .. to signify a parent directory.
Try:
File.Exists(#"..\..\..\..\..\..\" + #"test2.xml");
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();
If I have an executable called app.exe which is what I am coding in C#, how would I get files from a folder loaded in the same directory as the app.exe, using relative paths?
This throws an illegal characters in path exception:
string [ ] files = Directory.GetFiles ( "\\Archive\\*.zip" );
How would one do this in C#?
To make sure you have the application's path (and not just the current directory), use this:
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.getcurrentprocess.aspx
Now you have a Process object that represents the process that is running.
Then use Process.MainModule.FileName:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processmodule.filename.aspx
Finally, use Path.GetDirectoryName to get the folder containing the .exe:
http://msdn.microsoft.com/en-us/library/system.io.path.getdirectoryname.aspx
So this is what you want:
string folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + #"\Archive\";
string filter = "*.zip";
string[] files = Directory.GetFiles(folder, filter);
(Notice that "\Archive\" from your question is now #"\Archive\": you need the # so that the \ backslashes aren't interpreted as the start of an escape sequence)
Hope that helps!
string currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
string archiveFolder = Path.Combine(currentDirectory, "archive");
string[] files = Directory.GetFiles(archiveFolder, "*.zip");
The first parameter is the path. The second is the search pattern you want to use.
Write it like this:
string[] files = Directory.GetFiles(#".\Archive", "*.zip");
. is for relative to the folder where you started your exe, and # to allow \ in the name.
When using filters, you pass it as a second parameter. You can also add a third parameter to specify if you want to search recursively for the pattern.
In order to get the folder where your .exe actually resides, use:
var executingPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
As others have said, you can/should prepend the string with # (though you could also just escape the backslashes), but what they glossed over (that is, didn't bring it up despite making a change related to it) was the fact that, as I recently discovered, using \ at the beginning of a pathname, without . to represent the current directory, refers to the root of the current directory tree.
C:\foo\bar>cd \
C:\>
versus
C:\foo\bar>cd .\
C:\foo\bar>
(Using . by itself has the same effect as using .\ by itself, from my experience. I don't know if there are any specific cases where they somehow would not mean the same thing.)
You could also just leave off the leading .\ , if you want.
C:\foo>cd bar
C:\foo\bar>
In fact, if you really wanted to, you don't even need to use backslashes. Forwardslashes work perfectly well! (Though a single / doesn't alias to the current drive root as \ does.)
C:\>cd foo/bar
C:\foo\bar>
You could even alternate them.
C:\>cd foo/bar\baz
C:\foo\bar\baz>
...I've really gone off-topic here, though, so feel free to ignore all this if you aren't interested.
Pretty straight forward, use relative path
string[] offerFiles = Directory.GetFiles(Server.MapPath("~/offers"), "*.csv");