C# Combining two relative network paths - c#

The System.IO.Path Methods gave me some really weird results while combining two paths;
string Dir = "\\server1\\customers\\Test";
string path = "..\\..\\customers\\Test\\hello.pbt";
path = Path.Combine(Dir, path);
// path = "\\server1\\customers\\Test\\..\\..\\customers\\Test\\hello.pbt"
now i want to combine these paths:
path = "\\server1\\customers\\Test\\hello.pbt" // aim
but with the Path.GetFullPath method, it doesnt go backwards to the server as it should
path = Path.GetFullPath(path)
// path = "\\server1\\customers\\customers\\Test\\hello.pbt"
I Already tried all methods in described in Combining two relative paths with C# answers

The issue appears to be that .NET (and maybe Windows) does not view the parent of \\server1\customers to be \\server.
It looks like technically \\server is not a valid UNC path (i.e. you can't store files there directly).
var thisWorks = Directory.GetParent(Dir);
var thisIsNull = Directory.GetParent(Directory.GetParent(Dir).FullName);
Thus when you ask for ..\\..\\ it effectively ignores one of them since it deduces it can't go any higher up the directory tree...

Related

Parsing string containing Special Folder

I've allowed for custom paths to be entered and wanted the default to be something along the lines of:
%UserProfile%/Documents/foo, of course this needs to successfully parse the string and though it will work in Windows Explorer, I was wondering if I'm missing a library call or option for parsing this correctly.
DirectoryInfo's constructor certainly doesn't work, treating %UserProfile% like any other folder name.
If there is no good way, I'll manually parse it to substitute %foo% with the actual special folder location if it is in the Special Folders Enumeration.
Edit:
Code that does what I'm looking for (though would prefer a proper .NET library call):
var path = #"%UserProfile%/Documents/foo";
var specialFolders = Regex.Matches(path, "%(?<possibleSpecial>.+)%");
foreach (var spec in specialFolders.AsEnumerable())
{
if (Enum.TryParse<Environment.SpecialFolder>(spec.Groups["possibleSpecial"].Value, out var sf))
{
path = Regex.Replace(path, spec.Value, Environment.GetFolderPath(sf));
}
}
Use Environment.ExpandEnvironmentVariables on the path before using it.
var pathWithEnv = #"%UserProfile%/Documents/foo";
var path = Environment.ExpandEnvironmentVariables(pathWithEnv);
// your code...

C# winforms get nth folders from path

I've got an absolute path available to me. Say: C:/Program/CoreFiles/Folder1/Folder2/File.txt.
I need to copy that file to C:/Program/Projects/ProjectName/ but it needs to keep Folder1/Folder2/File.txt intact. So the end result should be C:/Program/Projects/ProjectName/Folder1/Folder2/File.txt.
My first attempt at solving this was to try and get the relative path between 2 absolute paths. Found Path.GetRelativePath(string, string) which obviously didn't help as it wasn't meant for WinForms. It would mess up anyway as the final result would be C:/Program/Projects/ProjectName/CoreFiles/Folder1/Folder2/File.txt.
The target directory is empty and I don't know the relative path to copy beforehand other than somehow getting that info out of the absolute path. Since File.Copy won't create folders that don't exist yet, I need to create them first. So how do I get the path that leads up to the file from the CoreFiles directory out of the absolute path?
The only working solution I can come up with is using regex to just replace CoreFiles with Projects/ProjectName in the path string and work with that. But that somehow seems the wrong approach.
Since you can't use Path.GetRelativePath. I suggest looking at another answer that describes how to do this yourself.
Like here...
How to get relative path from absolute path
Using the method in that answer, you can do the rest of your task as shown below.
string sourcePath = "C:/Program/CoreFiles/Folder1/Folder2/File.txt";
string sourceRoot = "C:/Program/CoreFiles/";
string destinationRoot = "C:/Program/Projects/ProjectName/";
// Use built-in .NET Path.GetRelativePath if you can. Otherwise use a custom function. Like here https://stackoverflow.com/a/340454/1812944
string relativePath = MakeRelativePath(sourceRoot, sourcePath);
// Combine the paths, and make the directory separators all the same.
string destinationPath = Path.GetFullPath(Path.Combine(destinationRoot, relativePath));
// Create nested folder structure for your files.
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
// Copy the file over.
File.Copy(sourcePath, destinationPath);

Get directory name from full directory path regardless of trailing slash

I need to get the directory name from its path regardless of any of having a trailing backslash. For example, user may input one of the following 2 strings and I need the name of logs directory:
"C:\Program Files (x86)\My Program\Logs"
"C:\Program Files (x86)\My Program\Logs\"
None of the following gives correct answer ("Logs"):
Path.GetDirectoryName(m_logsDir);
FileInfo(m_logsDir).Directory.Name;
They apparently analyze the path string and in the 1st example decide that Logs is a file while it's really a directory.
So it should check if the last word (Logs in our case) is really a directory; if yes, return it, if no (Logs might be a file too), return a parent directory. If would require dealing with the actual filesystem rather than analyzing the string itself.
Is there any standard function to do that?
new DirectoryInfo(m_logsDir).Name;
This may help
var result = System.IO.Directory.Exists(m_logsDir) ?
m_logsDir:
System.IO.Path.GetDirectoryName(m_logsDir);
For this we have a snippet of code along the lines of:
m_logsDir.HasFlag(FileAttribute.Directory); //.NET 4.0
or
(File.GetAttributes(m_logsDir) & FileAttributes.Directory) == FileAttributes.Directory; // Before .NET 4.0
Let me rephrase my answer, because you have two potential flaws by the distinguishing factors. If you do:
var additional = #"C:\Program Files (x86)\My Program\Logs\";
var path = Path.GetDirectoryName(additional);
Your output would be as intended, Logs. However, if you do:
var additional = #"C:\Program Files (x86)\My Program\Logs";
var path = Path.GetDirectoryName(additional);
Your output would be My Program, which causes a difference in output. I would either try to enforce the ending \ otherwise you may be able to do something such as this:
var additional = #"C:\Program Files (x86)\My Program\Logs";
var filter = additional.Split('\\');
var getLast = filter.Last(i => !string.IsNullOrEmpty(i));
Hopefully this helps.
Along the lines of the previous answer, you could enforce the trailing slash like this:
Path.GetDirectoryName(m_logsDir + "\");
Ugly but it seems to work - whether there's 0 or 1 slash at the end. The double-slash is treated like a single-slash by GetDirectoryName.

how to go one step backwards in path in C#

I want to get the path that my application is located in. I get the physical path by following code:
string filePath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
I get something like this as the result:
D:\\Projects\\UI\\IAC.SMS.MvcApp\\
I know that I can sepetare the string by "\" and combine them together. But is there an easy way to go one step back and get this?
D:\\Projects\\UI\\
You're looking for Directory.GetParent method.
var directoryName = Path.GetDirectoryName("D:\\Projects\\UI\\IAC.SMS.MvcApp\\");
var parentName = Directory.GetParent(directoryName).FullName;
Or
var parentName = new DirectoryInfo("D:\\Projects\\UI\\IAC.SMS.MvcApp\\").Parent.FullName;
Directory.GetParent will work in some cases, but it involves a performance penalty due to the creation of a DirectoryInfo object which will be populated with all sorts of information about the directory that may not be needed (e.g. creation time). I'd recommend Path.GetDirectoryName if all you need is the path, especially since with this method the path doesn't have to exist and you don't have to have permission to access it for the call to succeed.
var filePath = System.Web.HttpContext.Current.Request.PhysicalApplicationPath;
var parent = Path.GetDirectoryName(filePath);

What is difference between File.Exists("") and FileInfo exists

I have an *.exe file in \ProgramFiles(x86)\MyAppFolder.
In x86 application I check if the file exists (64 bit system).
simple:
bool fileExists = File.Exists(#"\ProgramFiles(x86)\MyAppFolder\Manager.exe");
The result is:
"fileExists == false" (the file is really there). It's Virtualization as I understand.That issue described here Its ok.
But next code:
bool fileExists = new FileInfo("\\Path").Exists;
"fileExists == true"
Why is the result different in 1st and 2nd cases?
var controller = new ServiceController(Product.ServiceName);
_manager.Enabled = controller.Status == ServiceControllerStatus.Running;
var info = new DirectoryInfo(Assembly.GetExecutingAssembly().Location);
var s = File.Exists(#"D:\TFS\GL_SOURCES\Teklynx_LPM\Dev\Server\Debug\Manager.exe");
string pathToManager = string.Empty;
if (info.Parent != null)
{
var pathToModule = info.Parent.FullName;
pathToManager = Path.Combine(pathToModule,"Manager.exe").Replace(" ",string.Empty);
}
//works good
var fileInfo = new FileInfo(pathToManager);
var managerSeparator = new ToolStripSeparator()
{
Visible = _manager.Visible = fileInfo.Exists // true
};
//Does not work
var managerSeparator = new ToolStripSeparator()
{
Visible = _manager.Visible = File.Exists(pathToManager ) // false
};
Thanks!
This is about the only difference and it has more to do with the nature of FileInfo:
FileInfo fileInfo = new FileInfo("myFile.txt"); // non-existent file
Console.WriteLine(fileInfo.Exists); // false
File.Create("myFile.txt");
Console.WriteLine(File.Exists("myFile.txt")); // true
Console.WriteLine(fileInfo.Exists); // false
So as you can see the value of fileInfo.Exists is cached the first time you use it.
Other than that, they do the same thing behind the scenes.
There is no difference, these methods use the exact same internal helper method inside the .NET Framework. Something you can see with a decompiler or the Reference Source source code, the helper method name is File.FillAttributeInfo().
Having duplication like this in the .NET Framework is pretty unusual, not exactly a Good Thing to have more than one way to accomplish the same thing. The File class is however special, it got added after a usability study conducted when .NET 1.0 shipped. The test subjects just had the basic BCL classes to work with, like FileStream and FileInfo, and otherwise only had MSDN documentation available. The test results were not very good, the File class got added to help programmers fall in the pit of success writing very basic file manipulation code. Like File.Exists() and File.ReadAllLines().
So it doesn't have anything to do with the classes, you are just using them wrong. Like not actually using the same path. Do go easy on the forward slashes, the mapping to backward slashes happens inside Windows and is inconsistently implemented in other code. Using // certainly doesn't do what you hope it does.
I've replicated your scenario using the below Linqpad script
var f = #"C:\Program Files (x86)\MyAppFolder\manager.exe";
bool fileExists = File.Exists(f);
bool fileInfoExists = new FileInfo(f).Exists;
fileExists.Dump();
fileInfoExists.Dump();
Ran this both when the file existed and when it did not and both produced the same output each time.
Maybe try this on your system and see if you still see differences.
in your first case, the file path is incorrect, you need spaces in "Program Files (x86)".
Secondly, the Path.Combine will return a Directory path so you'll end up with something like "C:\Program Files (x86)\MyAppFolder\Manager.exe\"
so it's a bad idea.
Both methods work the same way, so make sure you check that the path is correct.
The difference between File.Exists() and new FileInfo().Exists on it's behavior when full path (directory name + file name) is long:
var f = #"C:\Program Files (x86)\MyAppFolder\many_subfolders\manager.exe";
//f.length > 260 characters
bool fileExists = File.Exists(f); //return false, even if the file exists
// Throw exception: "The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters."
bool fileInfoExists = new FileInfo(f).Exists;
I just found this thread and wanted to update it as I had an issue with FileInfo vs File.Exists.
Let's take a scenario where we create a fileinfo object for a file that currently doesn't exist on a UNC share.
bool fileInfo = new FileInfo(#"\\uncshare\name\filename.txt");
At this point, the file does not exist, but if I create it using another tool (other code or outside my app) and then do this...
fileInfo.Refresh();
bool exists = fileInfo.Exists;
The result is false, it does not exist, even though it does and the fileInfo was refreshed.
To get the correct result requires..
bool exists = File.Exists(f);
Hope that helps others.

Categories

Resources