[C#] Path.Combine이 Path.DirectorySeparatorChar로 시작하는 파일 이름을 올바르게 연결하지 않는 이유는 무엇입니까?

로부터 직접 실행 창 Visual Studio에서 :

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

둘 다 동일해야합니다.

이전 FileSystemObject.BuildPath ()가 이런 식으로 작동하지 않았습니다 …



답변

이것은 문서가 말하는 것과 정확히 일치하기 때문에 일종의 철학적 질문입니다 (아마도 Microsoft 만 진정으로 대답 할 수 있음).

System.IO.Path.Combine

“path2에 절대 경로가 포함 된 경우이 방법은 path2를 반환합니다.”

다음 은 .NET 소스 의 실제 Combine 방법 입니다. 당신은 호출하는 것을 볼 수 있습니다 CombineNoChecks 다음 호출 IsPathRooted을 경로가 그렇다면 경로 2에 되돌아 :

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 ()을 호출하십시오.


답변

Path.Combine 메서드에 대한 .NET Reflector 에서 디스 어셈블 된 코드입니다 . 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;
}


답변

이 문제를 해결하고 싶었습니다.

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

또한이 문자열 처리를 수동으로 수행해야한다는 것이 상당히 성가신 것으로 생각되며, 그 이유에 관심이 있습니다.


답변

제 생각에는 이것은 버그입니다. 문제는 두 가지 유형의 “절대”경로가 있다는 것입니다. “d : \ mydir \ myfile.txt”경로는 절대적이고 “\ mydir \ myfile.txt”경로는 드라이브 문자가 없어도 “절대”로 간주됩니다. 제 생각에 올바른 동작은 두 번째 경로가 디렉토리 구분 기호로 시작하고 UNC 경로가 아닌 경우 첫 번째 경로에서 드라이브 문자를 추가하는 것입니다. 필요한 경우 원하는 동작을 가진 자체 도우미 래퍼 함수를 ​​작성하는 것이 좋습니다.


답변

에서 MSDN :

지정된 경로 중 하나가 길이가 0 인 문자열 인 경우이 메서드는 다른 경로를 반환합니다. path2에 절대 경로가 포함 된 경우이 메서드는 path2를 반환합니다.

귀하의 예에서 path2는 절대적입니다.


답변

Path.Combine은 본질적으로 쓸모가 없습니다. ” 라는 제목의 “Microsoft에 대한 증오”블로그에서 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);
    }
}

네임 스페이스 충돌해야한다는 일부 조언은 … 나는 갔다 Pathy약간으로, 그리고와 네임 스페이스 충돌을 피하기 위해 System.IO.Path.

편집 : null 매개 변수 검사 추가


답변

이 코드는 트릭을 수행해야합니다.

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