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

Kri*_*son 173 .net c# file

从Visual Studio中的立即窗口:

> Path.Combine(@"C:\x", "y")
"C:\\x\\y"
> Path.Combine(@"C:\x", @"\y")
"\\y"
Run Code Online (Sandbox Code Playgroud)

它们似乎都应该是一样的.

旧的FileSystemObject.BuildPath()没有以这种方式工作......

Rya*_*ndy 193

这是一个哲学问题(可能只有微软可以真正回答),因为它正在完成文档所说的内容.

System.IO.Path.Combine

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

这是 .NET源代码中的实际Combine方法.您可以看到它调用CombineNoChecks,然后在path2上调用IsPathRooted并返回该路径,如果是这样的话:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我使用这个修剪来获得所需的效果字符串strFilePath = Path.Combine(basePath,otherPath.TrimStart(new char [] {'\\','/'})); (11认同)
  • 我猜它可以通过这种方式轻松访问"当前工作目录"算法. (6认同)
  • 我确实将我的工作代码更改为`Path.Combine`只是为了安全,但后来它破了..这太愚蠢了:) (3认同)

Gul*_*zim 23

这是.NET Reflector for Path.Combine方法的反汇编代码.检查IsPathRooted功能.如果第二个路径是root(以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;
}
Run Code Online (Sandbox Code Playgroud)


anh*_*ppe 21

我想解决这个问题:

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);
Run Code Online (Sandbox Code Playgroud)

当然,所有路径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);
}
Run Code Online (Sandbox Code Playgroud)

我也认为这个字符串处理必须手动完成是非常烦人的,我对这背后的原因感兴趣.


Wed*_*dge 18

在我看来这是一个错误.问题是有两种不同类型的"绝对"路径.路径"d:\ mydir\myfile.txt"是绝对的,路径"\ mydir\myfile.txt"也被认为是"绝对的",即使它缺少驱动器号.在我看来,正确的行为是当第二条路径以目录分隔符开始时(并且不是UNC路径),从第一条路径前面加上驱动器号.我建议编写自己的帮助程序包装函数,如果需要,它具有您想要的行为.

  • 它符合规范,但它不是我所期望的. (5认同)

nic*_*ckd 8

来自MSDN:

如果其中一个指定路径是零长度字符串,则此方法返回另一个路径.如果path2包含绝对路径,则此方法返回path2.

在您的示例中,path2是绝对的.


Ami*_*adi 8

原因:

您的第二个 URL 被视为绝对路径,并且Combine如果最后一个路径是绝对路径,则该方法将仅返回最后一个路径。

解决方案:

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


erg*_*ack 7

根据Christian Graus在他的"我讨厌微软的事情"博客中提出的建议,题为" Path.Combine基本没用. ",这是我的解决方案:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有人建议命名空间应该碰撞,...我Pathy一点一点地去,并避免名称空间冲突System.IO.Path.

编辑:添加了空参数检查


ela*_*son 5

不知道实际的细节,我的猜测是它尝试加入,就像你可能加入相对的URI.例如:

urljoin('/some/abs/path', '../other') = '/some/abs/other'
Run Code Online (Sandbox Code Playgroud)

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


The*_*ing 5

这段代码应该可以解决问题:

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