2

Say, I have two path strings, an absolute one such as @"C:\abc\xyz", and a relative one such as @"..\def". How do I reliably combine those to yield the minimal form @"C:\abc\def"?

As the process should work for any forms of path that .NET's I/O API supports (i.e. the native paths of the system that .NET or Mono is currently running on, or alternatively something like UNC paths and the like), manual string manipulation seems to be too unreliably a solution.

In general, the tidy way to combine path strings is to use the Path.Combine method:

Path.Combine(@"C:\abc\xyz", @"..\def")

Unfortunately, it does not minimize the path and returns C:\abc\xyz\..\def.

As is suggested in a couple of other questions (e.g. this, or this), the GetFullPath method should be applied to the result:

Path.GetFullPath(Path.Combine(@"C:\abc\xyz", @"..\def"))

The problem with this is that GetFullPath actually looks at the file system rather than just handling the path string. From the docs:

The file or directory specified by path is not required to exist. (...) However, if path does exist, the caller must have permission to obtain path information for path. Note that unlike most members of the Path class, this method accesses the file system.

Therefore, GetFullPath doesn't work if I just want to minimize arbitrary path strings: Depending on whether the path happens to exist on the system where the application is running, the method might fail with a SecurityException if the user does not have access to the path.

So, how do I reliably combine path strings that could be processed by System.IO methods to return the shortest possible absolute path?

F-H
  • 663
  • 1
  • 10
  • 21
  • @Fabjan: [`Directory.GetParent`](https://msdn.microsoft.com/en-us/library/system.io.directory.getparent(v=vs.110).aspx) checks permissions, as well. Just try running it on [dotnetfiddle](https://dotnetfiddle.net/). – F-H Oct 08 '17 at 10:26

2 Answers2

1

You can use AbsolutePath of Uri class

var path = new Uri(Path.Combine(@"C:\abc\xyz", @"..\def")).AbsolutePath;
Eser
  • 12,346
  • 1
  • 22
  • 32
  • At least on [dotnetfiddle](https://dotnetfiddle.net/), this returns `C:/abc/def` instead of `C:\abc\def`. Now, I realize (based upon `Path.DirectorySeparatorChar` being `/`) dotnetfiddle may be internally using Mono on Linux - but in that case, shouldn't `C:\abc\xyz` be either an invalid path to start with, or `\` be interpreted as escape characters? – F-H Oct 08 '17 at 10:24
  • @F-H `C:/abc/def` is a valid path. You can try it by `new DirectoryInfo("c:/abc/xyz").GetFiles();` – Eser Oct 08 '17 at 10:27
  • Hmm ... at least [this answer](https://stackoverflow.com/a/1299356/5206621) insinuates the method based on an URI does not work exactly for using these path separator chars. I have asked for clarification there. In any case, a slight drawback could be that outputting such a path to users (which is also why I want to minimize it, for display reasons) may be slightly confusing as they would expect backslashes. – F-H Oct 08 '17 at 10:33
  • However, a real problem with this answer is that it destroys UNC paths. The server name will just not be present in the result. Maybe I can check whether the host is `localhost` or any of its aliases, and use `AbsolutePath` or `LocalPath` depending on that (?) – F-H Oct 08 '17 at 10:40
  • Update: With `LocalPath`, backslahes are used when run on Windows. So, `LocalPath` looks even more promising than `AbsolutePath`. – F-H Oct 10 '17 at 09:36
-1

If you want to use it via System.IO you will run into access violation problems at that point.

Why bother to increase the time till the exception comes?

Use try {} catch {} around GetFullPath and handle the error in place would be my suggestion.

So, how do I reliably combine path strings that could be processed by System.IO methods to return the shortest possible absolute path?

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • What error? I am not expecting any error. And why would I run into any access violation? – F-H Oct 08 '17 at 10:26
  • You do not want to use GetFullPath because -if the file exists- it might produce Exceptions due to actually going to the file system- if user can not access it. Then you want to use System.IO.-Stuff to access the exact same path - so you`ll run into the same problems. If the user has the rights, your fine,if not, exceptions. You just postpone the exception (and its handling) if one would happen. – Patrick Artner Oct 08 '17 at 11:03
  • "so you'll run into the same problems" - no, I won't. I didn't say I was going to make the `System.IO` calls at the same time as the string manipulation. They might indeed occur later (when permissions or other things about the directory structure at hand have changed), or in another user account (that has different permissions). Or, I might not even use these concrete strings with `System.IO` methods, yet I need them to be valid for `System.IO` methods in theory, if permissions were set. – F-H Oct 08 '17 at 11:27