在Visual Studio的即时窗口中:

> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"

看来它们应该是一样的。

旧的FileSystemObject.BuildPath()不是这样工作的……


由于不知道实际的细节,我猜测它尝试像连接相对uri那样连接。例如:

urljoin('/some/abs/path', '../other') = '/some/abs/other'

这意味着当您使用前面的斜杠连接路径时,实际上是将一个基底连接到另一个基底,在这种情况下,第二个基底优先。


从MSDN:

如果指定的路径之一是长度为零的字符串,则此方法返回另一个路径。如果path2包含一个绝对路径,该方法返回path2。

在你的例子中,path2是绝对的。


这是一个哲学问题(也许只有微软能真正回答这个问题),因为它正在做文档中所说的事情。

System.IO.Path.Combine

如果path2包含一个绝对路径,则此方法返回path2。

下面是. net源代码中的实际Combine方法。你可以看到它调用了CombineNoChecks,然后在path2上调用ispathooot,如果是的话返回该路径:

public static String Combine(String path1, String path2) {
    if (path1==null || path2==null)
        throw new ArgumentNullException((path1==null) ? "path1" : "path2");
    Contract.EndContractBlock();
    CheckInvalidPathChars(path1);
    CheckInvalidPathChars(path2);

    return CombineNoChecks(path1, path2);
}

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;
}

我不知道理由是什么。我想解决方案是剥离(或修剪)DirectorySeparatorChar从第二个路径的开始;也许你可以编写自己的Combine方法,然后调用Path.Combine()。


这是. net Reflector for Path的反汇编代码。结合的方法。检查ispathoot函数。如果第二个路径是根路径(以DirectorySeparatorChar开头),则返回第二个路径。

public static string Combine(string path1, string path2)
{
    if ((path1 == null) || (path2 == null))
    {
        throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
    }
    CheckInvalidPathChars(path1);
    CheckInvalidPathChars(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 + DirectorySeparatorChar + path2);
    }
    return (path1 + path2);
}


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;
}

In my opinion this is a bug. The problem is that there are two different types of "absolute" paths. The path "d:\mydir\myfile.txt" is absolute, the path "\mydir\myfile.txt" is also considered to be "absolute" even though it is missing the drive letter. The correct behavior, in my opinion, would be to prepend the drive letter from the first path when the second path starts with the directory separator (and is not a UNC path). I would recommend writing your own helper wrapper function which has the behavior you desire if you need it.


这个\表示“当前驱动器的根目录”。在你的例子中,它指的是当前驱动器根目录中的“test”文件夹。所以,这可以等于"c:\test"。


如果你想在不丢失任何路径的情况下组合这两条路径,你可以使用这个:

?Path.Combine(@"C:\test", @"\test".Substring(0, 1) == @"\" ? @"\test".Substring(1, @"\test".Length - 1) : @"\test");

或者用变量:

string Path1 = @"C:\Test";
string Path2 = @"\test";
string FullPath = Path.Combine(Path1, Path2.IsRooted() ? Path2.Substring(1, Path2.Length - 1) : Path2);

这两种情况都返回“C:\test\test”。

首先,我计算Path2是否以/开头,如果为真,返回不带第一个字符的Path2。否则,返回完整的Path2。


这段代码应该做到这一点:

        string strFinalPath = string.Empty;
        string normalizedFirstPath = Path1.TrimEnd(new char[] { '\\' });
        string normalizedSecondPath = Path2.TrimStart(new char[] { '\\' });
        strFinalPath =  Path.Combine(normalizedFirstPath, normalizedSecondPath);
        return strFinalPath;

我想解决这个问题:

string sample1 = "configuration/config.xml";
string sample2 = "/configuration/config.xml";
string sample3 = "\\configuration/config.xml";

string dir1 = "c:\\temp";
string dir2 = "c:\\temp\\";
string dir3 = "c:\\temp/";

string path1 = PathCombine(dir1, sample1);
string path2 = PathCombine(dir1, sample2);
string path3 = PathCombine(dir1, sample3);

string path4 = PathCombine(dir2, sample1);
string path5 = PathCombine(dir2, sample2);
string path6 = PathCombine(dir2, sample3);

string path7 = PathCombine(dir3, sample1);
string path8 = PathCombine(dir3, sample2);
string path9 = PathCombine(dir3, sample3);

当然,所有路径1-9最后都应该包含一个等效的字符串。这是我想出的PathCombine方法:

private string PathCombine(string path1, string path2)
{
    if (Path.IsPathRooted(path2))
    {
        path2 = path2.TrimStart(Path.DirectorySeparatorChar);
        path2 = path2.TrimStart(Path.AltDirectorySeparatorChar);
    }

    return Path.Combine(path1, path2);
}

我还认为这是相当恼人的字符串处理必须手动完成,我对这背后的原因很感兴趣。


这实际上是有意义的,在某种程度上,考虑到(相对)路径通常是如何处理的:

string GetFullPath(string path)
{
     string baseDir = @"C:\Users\Foo.Bar";
     return Path.Combine(baseDir, path);
}

// Get full path for RELATIVE file path
GetFullPath("file.txt"); // = C:\Users\Foo.Bar\file.txt

// Get full path for ROOTED file path
GetFullPath(@"C:\Temp\file.txt"); // = C:\Temp\file.txt

真正的问题是:为什么以“\”开头的路径被认为是“根路径”?这对我来说也很新鲜,但它在Windows上是这样工作的:

new FileInfo("\windows"); // FullName = C:\Windows, Exists = True
new FileInfo("windows"); // FullName = C:\Users\Foo.Bar\Windows, Exists = False

遵循Christian Graus在他的博客“我讨厌微软的事情”中的建议。合并本质上是无用的。”下面是我的解决方案:

public static class Pathy
{
    public static string Combine(string path1, string path2)
    {
        if (path1 == null) return path2
        else if (path2 == null) return path1
        else return path1.Trim().TrimEnd(System.IO.Path.DirectorySeparatorChar)
           + System.IO.Path.DirectorySeparatorChar
           + path2.Trim().TrimStart(System.IO.Path.DirectorySeparatorChar);
    }

    public static string Combine(string path1, string path2, string path3)
    {
        return Combine(Combine(path1, path2), path3);
    }
}

一些人建议名称空间应该冲突,…为了避免与System.IO.Path的名称空间冲突,我选择了Pathy。

编辑:增加空参数检查


这两个方法可以避免您意外地连接两个都有分隔符的字符串。

    public static string Combine(string x, string y, char delimiter) {
        return $"{ x.TrimEnd(delimiter) }{ delimiter }{ y.TrimStart(delimiter) }";
    }

    public static string Combine(string[] xs, char delimiter) {
        if (xs.Length < 1) return string.Empty;
        if (xs.Length == 1) return xs[0];
        var x = Combine(xs[0], xs[1], delimiter);
        if (xs.Length == 2) return x;
        var ys = new List<string>();
        ys.Add(x);
        ys.AddRange(xs.Skip(2).ToList());
        return Combine(ys.ToArray(), delimiter);
    }

原因:

第二个URL被认为是一个绝对路径,如果最后一个路径是一个绝对路径,Combine方法只会返回最后一个路径。

解决方案:

只需从第二个路径(/SecondPath到SecondPath)中删除前导斜杠/,它就会正常工作。


删除Path.Combine的第二个参数(path2)中的起始斜杠('\')。


我使用聚合函数强制路径组合,如下所示:

public class MyPath    
{
    public static string ForceCombine(params string[] paths)
    {
        return paths.Aggregate((x, y) => Path.Combine(x, y.TrimStart('\\')));
    }
}

正如Ryan所提到的,它正在做文档中所说的事情。

根据DOS时间,区分当前磁盘和当前路径。 \是根路径,但用于当前磁盘。

对于每个“磁盘”都有一个单独的“当前路径”。 如果您使用cd D:更改磁盘,则不会将当前路径更改为D:\,而是更改为:“D:\whatever\was\the\last\path\access \on\this\disk”…

因此,在windows中,文字@“\x”意味着:“CURRENTDISK:\x”。 因此路径。Combine(@"C:\x", @"\y")的第二个参数是根路径,不是相对路径,虽然不在已知磁盘中… 由于不知道哪个可能是«当前磁盘»,python返回“\\y”。

>cd C:
>cd \mydironC\apath
>cd D:
>cd \mydironD\bpath
>cd C:
>cd
>C:\mydironC\apath