C# get absolute path from `~` on Unix-like systems - c#

I'm building a C# app on Mac OS. It receives any path as an input and have to save a file by this path. The problem I faced is with paths relative to user directory, specified as ~.
I'm using following code using var s = File.Create(path); and there are few possibilities path parameter could be:
provided relative path e.g. filename.txt or ../filename.txt - it works and creates this file relative to current working directory.
provided absolute path e.g. /Users/username/Desktop/filename.txt - also works as expected
but providing path relative to user directory e.g. ~/Desktop/filename.txt - does not work. In this case File.Create is trying to combine absolute path like in case 1. It takes current working dir and simply adds my path like this /Users/username/project/~/Desktop/filename.txt. Which does not exist.
I tried to get absolute path from ~/Desktop with Path.GetFullPath("~/Desktop/filename.txt"). It results to the same /Users/username/project/~/Desktop/filename.txt. Same with Path.GetRelativePath("/", "~/Desktop/filename.txt");
Path.GetRelativePath("./", "~/Desktop/filename.txt"); returns not changed result.
Then tried Path.GetPathRoot("~/Desktop/filename.txt"). It gives just an empty string.
So the question, how in C# on Unix like host convert relative path like this ~/Desktop to absolute path like this /Users/username/Desktop?

You have to determine if the path starts with ~/ and, if it does, replace it with the path of the home directory. Here is a method that can do that:
public static string GetPath(string path) =>
(path.Length >= 2 && path.StartsWith("~/"))
? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), path.Substring(2))
: path;
Use it like this: GetPath("~/Desktop/filename.txt"). This will return /Users/username/Desktop/filename.txt (provided that your home directory is /Users/username).

Related

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);

How to get a file full path in c# with Path.GetFullPath

I am trying to get the full path a file by its name only.
I have tried to use :
string fullPath = Path.GetFullPath("excelTest");
but it returns me an incorrect path (something with my project path).
I have read somewhere here a comment which says to do the following:
var dir = Environment.SpecialFolder.ProgramFilesX86;
var path = Path.Combine(dir.ToString(), "excelTest.csv");
but I do not know where the file is saved , therefore I do not know its environment.
can someone help me how to get the full path of a file only by its name?
The first snippet (with Path.GetFullPath) does exactly what you want. It returns something with your project path because the program EXE file is located in the project\Bin\Debug path, which is therefore the "current directory".
If you want to search for a file on a drive, you can use Directory.GetFiles, which will recursively search for a file in a directory given a name pattern.
This returns all xml-files recursively :
var allFiles = Directory.GetFiles(path, "*.xml", SearchOption.AllDirectories);
http://msdn.microsoft.com/en-us/library/ms143316%28v=vs.100%29.aspx
http://msdn.microsoft.com/en-us/library/ms143448.aspx#Y252
https://stackoverflow.com/a/9830162/2196124
I guess you're trying to find file (like in windows search), right ?
I'd look into this question - you will find all files that has that string in their filename, and from there you can return full filepath.
var fileList = new DirectoryInfo(#"c:\").GetFiles("*excelTest*", SearchOption.AllDirectories);
And then just use foreach to do you manipulations, e.g.
foreach(string file in fileList)
{
// MessageBox.Show(file);
}
What you're looking for is Directory.GetFiles(), you can read up on it here. The gist of it is, you'll pass in the file path and the file name, and you'll get a string array back. In this instance, you can assume top level with C:\. It should be noted, that if nothing is found, the string array will be empty.
You have passed a relative file name to Path.GetFullPath. Microsoft documentation states:
If path is a relative path, GetFullPath returns a fully qualified path that can be based on the current drive and current directory. The current drive and current directory can change at any time as an application executes. As a result, the path returned by this overload cannot be determined in advance.
You cannot get the same full path name from a relative path unless your current directory is the same each time you invoke the function.

Get absolute path from relative path c#

I have a file in a folder somewhere on my computer and I have a second file where the relative path to the first file is noticed.
Now I want to figure out the absolute path.
GetFullPath doesn't work because the second file is not in the directory where the program runs.
Is there an opportunity to say from which directory the "GetFullPath" function should start, to get the right absolute path?
You can use the static methods of Path to calculate the resulting path:
string fullPathToSecondFile = "c:\\test\\subtestsecond\\secondfile.txt";
string relativePath = "..\\subtestfirst\\firstfile.txt";
string fullPathToFirstFile = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(fullSecondPath), relativePath));
This results in c:\test\subtestfirst\firstfile.txt
What happens is that you combine a relative path to a absolute one. This results in c:\test\subtestsecond\..\subtestfirst\firstfile.txt.
In the second step Path.GetFullPath() normalizes the string to the result shown above.

Can't get my head round relative path

This is probably something mind-numbingly obvious, but I'm new to c# so be gentle...
I have an application which (in theory) parses a text file into an array. Despite the text file being a peer of the aspx file I can't get the relative path right. Don't know if it makes any difference (I'd assume not) but I'm using code-behind.
My folder structure looks like this:
default.aspx
default.aspx.cs
default.aspx.designer.cs
album.cs
albums.txt
web.config
And this is the code I'm using:
protected void Page_Load(object sender, EventArgs e)
{
string[] allLines = File.ReadAllLines(#"Albums.txt");
Album[] Albums = new Album[allLines.Length];
for (int i = 0; i < allLines.Length; i++)
{
string[] lineSplit = allLines[i].Split(',');
Albums[i] = new Album();
Albums[i].ID = Convert.ToInt32(lineSplit[0]);
Albums[i].title = lineSplit[1];
Albums[i].keyName = lineSplit[2];
}
}
However, when I build it I get an error saying albums.txt can not be found, and it fails.
Any pointers would be greatly appreciated.
Ben
Server.MapPath specifies the relative or virtual path to map to a physical directory.
* Server.MapPath(".") returns the current physical directory of the file (e.g. aspx) being executed
* Server.MapPath("..") returns the parent directory
* Server.MapPath("~") returns the physical path to the root of the application
* Server.MapPath("/") returns the physical path to the root of the domain name (is not necessarily the same as the root of the application)
An example:
Let's say you pointed a web site application (http://www.example.com/) to
C:\Inetpub\wwwroot
and installed your shop application (sub web as virtual directory in IIS, marked as application) in
D:\WebApps\shop
If, for example, you call Server.MapPath in following request:
http://www.example.com/shop/product/GetProduct.aspx?id=2342
then,
* Server.MapPath(".") returns D:\WebApps\shop\products
* Server.MapPath("..") returns D:\WebApps\shop
* Server.MapPath("~") returns D:\WebApps\shop
* Server.MapPath("/") returns C:\Inetpub\wwwroot
* Server.MapPath("/shop") returns D:\WebApps\shop
If Path starts with either a forward (/) or backward slash (), the MapPath method returns a path as if Path were a full, virtual path.
If Path doesn't start with a slash, the MapPath method returns a path relative to the directory of the request being processed.
Note: in C#, # is the verbatim literal string operator meaning that the string should be used "as is" and not be processed for escape sequences.
Server.MapPath("."), Server.MapPath("~"), Server.MapPath(#"\"), Server.MapPath("/"). What is the difference?
Instead of just the filename, use Server.MapPath(filename) to get the full path to the file.
If the file is located in a different directory, you could use Server.MapPath("~/path/to/the/file.txt"), where ~ corresponds to the root folder of your web application.
ReadAllLines takes an absolute path - what you've provided is a relative path. Server.MapPath is used to translate relative paths to absolute ones. Server.MapPath("~/Albums.txt") would give the right value irrespective of where the code resides. Also, by putting the file under ~\App_Data\ you can prevent direct downloads of the file itself as well as insulating the application against repeated updates to that file while the application is running (updates to App_Data contents don't generate File Change Notifications).

how can i resolve a relative path in both a web/windows app in c#

I have an assmebly that will be used in both a desktop app and an asp.net website.
I need to deal with relative paths (local files, not urls) in either situation.
How can i implement this method?
string ResolvePath(string path);
Under a web envronment, id expect the method to behave like this (where d:\wwwroot\mywebsite is the folder iis points at):
/folder/file.ext => d:\wwwroot\mywebsite\folder\file.ext
~/folder/file.ext => d:\wwwroot\mywebsite\folder\file.ext
d:\wwwroot\mywebsite\folder\file.ext => d:\wwwroot\mywebsite\folder\file.ext
for a desktop environment: (where c:\program files\myprogram\bin\ is the path of the .exe)
/folder/file.ext => c:\program files\myprogram\bin\folder\file.ext
c:\program files\myprogram\bin\folder\file.ext => c:\program files\myprogram\bin\folder\file.ext
I'd rather not inject a different IPathResolver depending on what state its running in.
How do I detect which environment I'm in, and then what do i need to do in each case to resolve the possibly-relative path?
Thanks
I don't think the original question was answered.
Let assume you want "..\..\data\something.dat" relative to, lets say the executable in "D:\myApp\source\bin\". Using
System.IO.Path.Combine(Environment.CurrentDirectory, relativePath);
will simply return "D:\myApp\source\bin..\..\data\something.dat" which is also easily obtained by simply concatenating strings. Combine doesn't resolve paths, it handles trailing backslashes and other trivialities. He probably wants to run:
System.IO.Path.GetFullPath("D:\myApp\source\bin..\..\data\something.dat");
To get the a resolved path: "D:\myApp\data\something.dat".
The website binaries are copied to a temp folder when the application runs - so you usually can't get the relative path from the excecuting assembly.
This may not be a sensible way of doing this - but what I did to solve this problem was something like this:
if (filepath.StartsWith("~"))
{
filepath = HttpContext.Current.Server.MapPath(filepath);
}
else
{
filepath = System.IO.Path.Combine(Environment.CurrentDirectory, filepath);
}
This is because on the web version - a relative path has a ~ at the front - so I can tell if it's come from the web.config or the App.config.
As mentioned in John's comment, relative to what? You can use System.IO.Path.Combine method to combine a base path with a relative path like:
System.IO.Path.Combine(Environment.CurrentDirectory, relativePath);
You can replace Environment.CurrentDirectory in the above line with whatever base path you want.
You could store the base path in the configuration file.

Categories

Resources