43

To my surprise, this code does not produce expected results:

var basePath = @"\\server\BaseFolder";
var relativePath = @"\My\Relative\Folder";

var combinedPath = Path.Combine(basePath, relativePath);

The result is \My\Relative\Folder instead of the expected \\server\BaseFolder\My\Relative\Folder.

Why is this? What's the best way to combine relative paths that may or may not have a slash in them?

EDIT: I'm aware that I can just do string manipulation on relativePath to detect and remove a starting slash. Is there a safer way of doing this (I thought Path.Combine was supposed to be the safe way) that will account for backslashes and frontslashes?

Brandon
  • 13,956
  • 16
  • 72
  • 114

3 Answers3

50

Drop the leading slash on relativePath and it should work.

The reason why this happens is that Path.Combine is interpreting relativePath as a rooted (absolute) path because, in this case, it begins with a \. You can check if a path is relative or rooted by using Path.IsRooted().

From the doc:

If the one of the subsequent paths is an absolute path, then the combine operation resets starting with that absolute path, discarding all previous combined paths.

Restore the Data Dumps
  • 38,967
  • 12
  • 96
  • 122
  • 24
    What a stupid thing.. If I need to trim start/end of the string etc. why would I use Path.Combine in the first place? – yakya Aug 31 '18 at 11:21
  • 4
    Is there a single use case in history where this is how anybody would want this to work?? – niico Jan 23 '21 at 01:24
23

Paths that start with a slash are interpreted as being absolute rather than relative. Simply trim the slash off if you want to guarantee that relativePath will be treated as relative.

var basePath = @"\\server\BaseFolder";
var relativePath = @"\My\Relative\Folder";

var combinedPath = Path.Combine(basePath, relativePath.TrimStart('/', '\\'));
wixardy
  • 35
  • 1
  • 5
Greg
  • 23,155
  • 11
  • 57
  • 79
6

According to this doc on Path.Combine the remark states it's best to use Path.Join() for this scenario where the user may have entered values. Looks like it was introduced with .NET Core 3.0

Path.Join(basePath, relativePath);

Seems like the only difference is this explicit scenario where we don't want to regard any of the paths we are combining as potential root paths.

Unlike the Combine method, the Join method does not attempt to root the returned path. (That is, if path2 or path2 or path3 is an absolute path, the Join method does not discard the previous paths as the Combine method does.

James Esh
  • 2,219
  • 1
  • 24
  • 41
  • This doesn't work, it adds another slash to the root folder. For example, ``path1 = \\files\, path2 = \filename.txt, result = \\files\\filename.txt`` – Rod Talingting Apr 29 '22 at 16:06
  • It is true that it doesn't remove the extra slashes, but on Windows and Unix (read: essentially everywhere) that's fine: https://unix.stackexchange.com/a/1919 – James Esh Apr 29 '22 at 21:24
  • 1
    Just to point out that this is not available in .net framework – ilCosmico Aug 18 '22 at 07:36