1

I notice that when I use Path.GetFullPath(Path.Combine(@"c:\folder\","\subfolder\file.txt")) it returns a path c:\subfolder\file.txt, instead of the expected combined path c:\folder\subfolder\file.txt. It seems like having a '\' on the second combined input isn't handled by these methods. Has anyone come across this and found a better solution for merging paths?

var test1 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @".\test1.txt"));
var test2 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @"\test2.txt"));//
var test3 = Path.GetFullPath(Path.Combine(@"C: \users\dev\desktop\testfiles\", @"test3.txt"));
var test4 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\",@".\XXX\test4.txt"));
var test5 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @"\XXX\test5.txt"));//
var test6 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @"XXX\test6.txt"));
var test7 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @"\somefile\that\doesnt\exist.txt"));//

Results in

test1 is "C:\users\dev\desktop\testfiles\test1.txt"
test2 is wrong "\test2.txt"
test3 is "C: \users\dev\desktop\testfiles\test3.txt"
test4 is "C:\users\dev\desktop\testfiles\XXX\test4.txt"
test5 is wrong "c:\XXX\test5.txt"
test6 is "C:\users\dev\desktop\testfiles\XXX\test6.txt"
test7 is wrong "c:\somefile\that\doesnt\exist.txt"

Basically what I'm doing is combining a source path with individual file paths from a text file so that I can copy these files to a destination, and I want to maintain subfolder hierarchy.

e.g. common scenario of the files list being the same, but wanting to reference a specific source folder version.

source path + individual file path
\\myserver\project\1.x + \dll\important.dll

which should be copied to a destination in the same manner

c:\myproject\ + \dll\important.dll

So there would be variables; source, destination, files[array or list]

My current way forward is to use String.TRIM() method to remove special chars . \ / before combining paths with Path.Combine, Path.GetFullPath. But I thought maybe someone has realized a better way for a similar scenario.

It's also a pain creating the subfolders in the destination, basically im using String.LastIndexOf(@'\') to separate the filename from the foldername. Which is also seems a little sketchy, but a better way is beyond my experience.

Similar question: Path.Combine absolute with relative path strings


Thanks to the feedback I now know that \file.txt is considered a fully qualified (absolute) path, which is why the combine method works that way.

A file name is relative to the current directory if it does not begin with one of the following:

A UNC name of any format, which always start with two backslash characters ("\\"). For more information, see the next section.
A disk designator with a backslash, for example "C:\" or "d:\".
A single backslash, for example, "\directory" or "\file.txt". This is also referred to as an absolute path.

https://msdn.microsoft.com/en-nz/library/windows/desktop/aa365247(v=vs.85).aspx#fully_qualified_vs._relative_paths

Community
  • 1
  • 1
plumdog
  • 355
  • 5
  • 9
  • 1
    It seems that the first backslash in the second part of your 'combine' method is making your path return to the 'c:\' as basepath. Maybe you can look to filter that first '\' out? – Anthony Dekimpe Feb 07 '16 at 06:24
  • https://msdn.microsoft.com/en-nz/library/windows/desktop/aa365247(v=vs.85).aspx#fully_qualified_vs._relative_paths – plumdog Feb 07 '16 at 07:49

2 Answers2

3

Based on the MSDN Documentation, this is expected behavior.

If path2 does not include a root (for example, if path2 does not start with a separator character or a drive specification), the result is a concatenation of the two paths, with an intervening separator character. If path2 includes a root, path2 is returned.

Seperator characters are discussed in this MSDN article.

So let's take a look at your test cases:

var test1 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @".\test1.txt"));
var test2 = Path.GetFullPath(Path.Combine(@"C:\users\dev\desktop\testfiles\", @"\test2.txt"));

Test1 is behaving correctly because it is taking the . as part of a valid file path and using it in combination with the first parameter to generate the combined path.

Test2 is behaving as expected because the \ is a separator character, so as described it is returned without the first parameter.

drneel
  • 2,887
  • 5
  • 30
  • 48
  • Thanks for the clarification, that shows the method is working as expected. I guess it shows that I don't understand clearly what an absolute path is. Since I didn't think "\test2.txt" qualified as an absolute path. I will learn more about it. Thanks – plumdog Feb 07 '16 at 07:41
1

There is no functions that you like to use in .Net framework - trimming path or ensuring that relative path starts with ".\" your real options (probably library that does it exists somewhere).


Why code does not behave the way you like (not "wrong", just not meeting your unexpected expectations).

Combine need to decide which part of left path will stay and which will be replaced. It uses regular file system conventions to decide that (".", "..", "\" have special meaning for file paths)

Meaning of path starting with:

  • @"\" or"/" - starting from the root of current device - this covers most cases that you don't like
  • @".\" - means from current directory (hence after combining and normalizing it will behave exactly as you want)
  • `@"..\" (possible multiple "go up") - go up one folder - this is another case you'll likely disagree with.
  • any character that is not '/' or @'\' - file name or path from current folder

Also note that path ending on anything but "/" or @"\" is treated by Path.Combine as file path and when combined with other path it will lose last segment.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • Thank you for confirming that .NET doesn't have anything built in to solve this one. That's what I was mainly trying to figure out, was if there was a better way available. I wanted to accept your answer also but can only accept one, appreciate your reply. You are right that it's my expectation of the combine method that's wrong, the method works as designed now I realise that \file.txt is actually an absolute path – plumdog Feb 07 '16 at 07:43