I don't quite see the difference.
What could Path.Combine do better than perfectly working string concatenation?
I guess it's doing something very similar in the background.
Can anyone tell me why it is so often preferred?
Path.Combine uses the Path.PathSeparator and it checks whether the first path already has a separator at the end so it will not duplicate the separators. Additionally, it checks whether the path elements to combine have invalid chars.
Path.Combine does more things than just a string concatenation. If you look at the source code;
Here is the implementation
public static string Combine(string path1, string path2)
{
if (path1 == null || path2 == null)
{
throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
}
Path.CheckInvalidPathChars(path1, false);
Path.CheckInvalidPathChars(path2, false);
return Path.CombineNoChecks(path1, path2);
}
private static string CombineNoChecks(string path1, string path2)
{
if (path2.Length == 0)
{
return path1;
}
if (path1.Length == 0)
{
return path2;
}
if (Path.IsPathRooted(path2))
{
return path2;
}
char c = path1[path1.Length - 1];
if (c != Path.DirectorySeparatorChar && c != Path.AltDirectorySeparatorChar && c != Path.VolumeSeparatorChar)
{
return path1 + Path.DirectorySeparatorChar + path2;
}
return path1 + path2;
}
According to this documentation Path.Combine internally performs a string concatenation using +-Operator.
private static String CombineNoChecks(String path1, String path2)
{
if (path2.Length == 0)
return path1;
if (path1.Length == 0)
return path2;
if (IsPathRooted(path2))
return path2;
char ch = path1[path1.Length - 1];
if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar && ch != VolumeSeparatorChar)
return path1 + DirectorySeparatorCharAsString + path2;
return path1 + path2;
}
System.IO.Path.Combine() Automatically combines multiple paths to a single string by using the correct path separator i.e. forward slash '/' or backward slash '' compatible to the operating systems OS. On the other hand, using string concatenation will do the same but we will need to explicitly (manually) add correct path separator after or before the paths respectively to the paths. forexample:
string virtualPath = "/data/directory" +"/" + "video.mp4";
while using Path.Combine(),
string virtualPath = Path.Combine("/data/directory", "video.mp4");
Both the Path.Combine() and string concatenation method produce the same result but Path.Combine() method offers a more elegant method to combine paths.
A lot of answers here are incorrectly stating that it illiminiate the double path seperator if "one path already has a separator". If you study the .Net source code of Path.Combine() included in some of the answers as well, you will notice the following important facts.
internal static string CombineNoChecks(string path1, string path2)
{
if (path2.Length == 0)
return path1;
if (path1.Length == 0)
return path2;
if (IsPathRooted(path2))
return path2;
char ch = path1[path1.Length - 1];
if (ch != DirectorySeparatorChar && ch != AltDirectorySeparatorChar && ch != VolumeSeparatorChar)
return path1 + DirectorySeparatorCharAsString + path2;
return path1 + path2;
}
Path.Combine:
DOES check for a "trailing separator" at the end of the FIRST path. It DOES add one before combining the paths. This is the big benefit if you require external code or user input for the "root" path. Since you don't need to do a check if a trailing separator is included (and potentially unwantedly adding it in a concatenated scenario).
If the SECOND path provided ALREADY have a LEADING separator, it simply return the second path, or if you use an array of path pieces (directory names) everything from the last entry with a leading slash. (So: Path.Combine("c:\temp", "\abc1") == "\abc1")
It DOES validate the paths and throw an Exception if invalid chars is used in the path.
If your returned path requires a trailing slash, using Path.Combine() to add a TRAILING slash to your path is BAD. it will simply return the trailing slash. (So: Path.Combine("C:\Temp", "\" == "\").
So when using Path.Combine(), trailing separators are SAFE but optional, and leading separators are BAD for everything after the first ("root") value.
The key is in the check for "IsPathRooted" that simply returns the second path:
// Tests if the given path contains a root. A path is considered rooted
// if it starts with a backslash ("\") or a drive letter and a colon (":").
//
[Pure]
public static bool IsPathRooted(String path) {
if (path != null) {
CheckInvalidPathChars(path);
int length = path.Length;
if ((length >= 1
&& (path[0] == DirectorySeparatorChar
|| path[0] == AltDirectorySeparatorChar))
|| (length >= 2 && path[1] == VolumeSeparatorChar))
return true;
}
return false;
}
Path.Combinewould work unchanged on Linux & Mac when using mono.