227 Stimmen

Warum verkettet Path.Combine Dateinamen, die mit Path.DirectorySeparatorChar beginnen, nicht richtig?

Von der Sofortiges Fenster in Visual Studio:

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

Es scheint, dass sie beide gleich sein sollten.

Das alte FileSystemObject.BuildPath() funktionierte nicht auf diese Weise...

240voto

Ryan Lundy Punkte 195074

Dies ist eine Art philosophische Frage (die vielleicht nur Microsoft wirklich beantworten kann), da es genau das tut, was in der Dokumentation steht.

System.IO.Path.Combine

"Wenn path2 einen absoluten Pfad enthält, gibt diese Methode path2 zurück."

Hier ist die eigentliche Combine-Methode aus dem .NET-Quellcode. Sie können sehen, dass es aufruft CombineNoChecks , die dann die IsPathRooted auf Pfad2 und gibt diesen Pfad zurück, wenn dies der Fall ist:

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

Ich weiß nicht, was die Gründe dafür sind. Ich schätze, die Lösung ist, DirectorySeparatorChar vom Anfang des zweiten Pfades zu entfernen (oder zu trimmen); vielleicht schreiben Sie Ihre eigene Combine-Methode, die das tut und dann Path.Combine() aufruft.

30voto

anhoppe Punkte 3769

Ich wollte dieses Problem lösen:

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

Natürlich sollten alle Pfade 1-9 am Ende eine entsprechende Zeichenkette enthalten. Hier ist die PathCombine-Methode, die ich entwickelt habe:

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

Ich denke auch, dass es ziemlich ärgerlich ist, dass diese Zeichenkettenbehandlung manuell erfolgen muss, und ich würde mich für den Grund dafür interessieren.

25voto

Gulzar Nazim Punkte 51098

Dies ist der disassemblierte Code von .NET-Reflektor für die Methode Path.Combine. Prüfen Sie die Funktion IsPathRooted. Wenn der zweite Pfad verwurzelt ist (beginnt mit einem DirectorySeparatorChar), wird der zweite Pfad so zurückgegeben, wie er ist.

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

24voto

Wedge Punkte 19070

Meiner Meinung nach ist dies ein Fehler. Das Problem ist, dass es zwei verschiedene Arten von "absoluten" Pfaden gibt. Der Pfad "d: \mydir\myfile.txt " ist absolut, der Pfad " \mydir\myfile.txt " wird ebenfalls als "absolut" betrachtet, auch wenn der Laufwerksbuchstabe fehlt. Das korrekte Verhalten wäre meiner Meinung nach, den Laufwerksbuchstaben des ersten Pfades voranzustellen, wenn der zweite Pfad mit dem Verzeichnis-Trennzeichen beginnt (und kein UNC-Pfad ist). Ich würde empfehlen, eine eigene Wrapper-Hilfsfunktion zu schreiben, die das von Ihnen gewünschte Verhalten aufweist, wenn Sie es brauchen.

11voto

ergohack Punkte 1146

Unter Christian Graus Ratschläge in seinem Blog "Dinge, die ich an Microsoft hasse" mit dem Titel " Path.Combine ist im Wesentlichen nutzlos. ", hier ist meine Lösung:

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

Einige raten, dass die Namensräume kollidieren sollten, ... Ich habe mich für Pathy und zur Vermeidung von Namensraumkollisionen mit System.IO.Path .

Editar : Null-Parameter-Prüfungen hinzugefügt

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X