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;
}
Volumelessshould be callesOSLesssince this is an OS-free path, right? \$\endgroup\$Urior 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\$Uriisn'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 yourOSPathdoes with Windows & Unix etc. \$\endgroup\$WindowsorUnixproperties which are virtually hardcoded paths representations. \$\endgroup\$/inAbsolutePathand\` inLocalPath`. 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\$