We are all tremendously happy about back slashes in Windows file systems and do not think that their sole purpose is to make life complicated for smart people who are capable of using different OS. Upvote if disagree [ :) ].
Converting paths from/to Windows backward slashes is a pretty monotonous task. Here is a library class to help with it. GitHub
OSPath path = @"/foo\bar.txt";
// Windows output
WriteLine(path); // \foo\bar.txt
WriteLine(path.Windows); // \foo\bar.txt
WriteLine(path.Unix); // /foo/bar.txt
// MacOS output
WriteLine(path); // /foo/bar.txt
WriteLine(path.Windows); // \foo\bar.txt
WriteLine(path.Unix); // /foo/bar.txt
It also helps converting between relative and absolute paths:
OSPath ap = "/foo/bar";
WriteLine(ap.Relative.Unix); // foo/bar
WriteLine(ap.Absolute.Unix); // /foo/bar
OSPath rp = "foo/bar";
WriteLine(rp.Relative.Unix); // foo/bar
WriteLine(rp.Absolute.Unix); // /foo/bar
And to perform path arithmetic (Windows output):
OSPath root = @"/foo\bar";
WriteLine(root + "file.txt"); // \foo\bar\file.txt
WriteLine(root + "file.txt" - root); // file.txt
Library class is:
public class OSPath
{
public static readonly OSPath Empty = "";
public static bool IsWindows => DirectorySeparatorChar == '\\';
public OSPath(string path)
{
Path = path.Trim();
}
public static implicit operator OSPath(string path) => new OSPath(path);
public static implicit operator string(OSPath path) => path.Normalized;
public override string ToString() => Normalized;
protected string Path { get; }
public string Normalized => IsWindows ? Windows : Unix;
public string Windows => Path.Replace('/', '\\');
public string Unix => Volumeless.Path.Replace('\\', '/');
public OSPath Relative => Volumeless.Path.TrimStart('/', '\\');
public OSPath Absolute => IsAbsolute ? this : "/" + Relative;
public bool IsAbsolute => IsPathRooted(Path);
public bool HasVolume => IsAbsolute && Path[1] == ':';
public OSPath Volumeless => HasVolume
? (this - GetPathRoot(Path)).Absolute
: this;
public OSPath Parent => GetDirectoryName(Path);
public bool Contains(OSPath path) =>
Normalized.StartsWith(path);
public static OSPath operator +(OSPath left, OSPath right) =>
new OSPath(Combine(left, right.Relative));
public static OSPath operator -(OSPath left, OSPath right) =>
left.Contains(right)
? new OSPath(left.Normalized.Substring(right.Normalized.Length)).Relative
: left;
}
Volumeless
should be callesOSLess
since this is an OS-free path, right? \$\endgroup\$Uri
or something like that. Pretty common for stable utility classes with no dependencies and not many reasons to change. 2) Yep, Volumeless sounds ugly, agree :) \$\endgroup\$Uri
isn't a good example becaue unlike your class, it's a generic representation or the URI concept. It does not hardcode e.g. schemas like yourOSPath
does with Windows & Unix etc. \$\endgroup\$Windows
orUnix
properties which are virtually hardcoded paths representations. \$\endgroup\$/
inAbsolutePath
and\` in
LocalPath`. I have general representation of OS Path. Actually, without anything asking for polymorphic behavior - I need Unix representation all the time for persistence, etc. \$\endgroup\$