为什么Path.Combine无法正确连接以Path.DirectorySeparatorChar开头的文件名?

时间:2020-03-05 18:50:25  来源:igfitidea点击:

从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:

If one of the specified paths is a zero-length string, this method returns the other path. If path2 contains an absolute path, this method returns path2.

在示例中,path2是绝对的。

回答

这是一个哲学问题(也许只有Microsoft才能真正回答),因为它确实在按照文档中的说明进行操作。

System.IO.Path.Combine

"如果path2包含绝对路径,则此方法返回path2. "

这是来自.NET源的实际Combine方法。我们可以看到它调用CombineNoChecks,然后在path2上调用IsPathRooted并返回该路径(如果是)。

我不知道这是什么理由。我猜解决方案是从第二条路径的开头剥离(或者修剪)DirectorySeparatorChar;也许编写自己的Combine方法来执行该操作,然后调用Path.Combine()。

回答

这是.NET Reflector中用于Path.Combine方法的反汇编代码。检查IsPathRooted函数。如果第二个路径是根目录(以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;
}

回答

我认为这是一个错误。问题在于存在两种不同类型的"绝对"路径。路径" d:\ mydir \ myfile.txt"是绝对路径,路径" \ mydir \ myfile.txt"也被视为"绝对路径",即使它缺少驱动器号。我认为正确的行为是,当第二个路径以目录分隔符开头(而不是UNC路径)时,在第一个路径前添加驱动器号。我建议编写自己的辅助包装函数,如果需要的话,该函数具有所需的行为。