Ще работи ли този метод за създаване на относителни пътища?

Тъй като .NET не включва API за създаване на относителни пътища, вместо това използвах метода MakeRelativeUri на Uri. Това работи, но съм срещал няколко случая, в които не се дължи на факта, че Uri е екраниран. Така че поправих и това:

public static string MakeRelativePath(string basePath, string tgtPath) {
    return
        Uri.UnescapeDataString(
            new Uri(basePath, UriKind.Absolute)
                .MakeRelativeUri(new Uri(tgtPath, UriKind.Absolute))
            .ToString()
        ).Replace('/', Path.DirectorySeparatorChar);
}

Тази версия изглежда работи, но ме кара да се чувствам малко недоумяващ: няма ли валидни пътеки към локалната файлова система, които това безвъзмездно освобождаване може да повреди?

Свързано: Как да получите относителен път от absolute path Отговорите на този въпрос изобщо не засягат проблема с необичайните герои и бягството и като такива не отговарят на този въпрос.


person Eamon Nerbonne    schedule 05.06.2011    source източник
comment
възможен дубликат на Как да получа относителен път от абсолютен път   -  person David Heffernan    schedule 05.06.2011
comment
@Eamon Тук има някои добри отговори: stackoverflow.com/questions/275689/ Ако бях аз, щях да избера решението, което P/извиква до PathRelativePathTo()   -  person David Heffernan    schedule 05.06.2011
comment
Да, виждам отговор, който също използва Uri, макар и без бягство, т.е. borked. P/Извикване; добре, това е бавно и зависи от платформата, което означава, че може да се натъкнете на проблеми с x86/x64, проблеми с непълно доверие и разбира се неща като silverlight/XNA не го поддържат непременно. Ще свърши работа, но не е първият ми избор.   -  person Eamon Nerbonne    schedule 05.06.2011
comment
@Eamon Виждам това. Аз съм ориентиран към Windows и P/Invoking е добре. Не виждам скоростта като проблем - няма да извиквате това в горещия цикъл на вашето приложение, нали?!!   -  person David Heffernan    schedule 05.06.2011
comment
Направих нещо подобно в индексатор за персонализирано търсене, но само при няколкостотин хиляди пътеки това вероятно не е голям проблем. Все още; хубаво е да не се тревожиш на първо място. Между другото, PathRelativePathTo прави ли I/O и/или нормализиране? MSDN не казва.   -  person Eamon Nerbonne    schedule 05.06.2011
comment
PathRelativePathTo не засяга файловата система, доколкото ми е известно. Това е чисто текстово. Ако искате да знаете как се прилага, винаги можете да погледнете изходния код на Wine!   -  person David Heffernan    schedule 05.06.2011
comment
Благодаря, наистина обичам такива малки идеи!   -  person Eamon Nerbonne    schedule 05.06.2011


Отговори (1)


Вместо екраниране, премахване на екраниране и замяна, можете просто да използвате основния алгоритъм, използван от System.Uri и метода PathDifference. Ето го, възстановен чрез Reflector и модифициран за малко по-добра четливост. Той също така е модифициран, за да използва обратни наклонени черти за пътеки в стил DOS вместо наклонени черти за URI адреси и сравнението винаги е без значение за малки и големи букви.

static string PathDifference(string path1, string path2)
{
    int c = 0;  //index up to which the paths are the same
    int d = -1; //index of trailing slash for the portion where the paths are the same

    while (c < path1.Length && c < path2.Length)
    {
        if (char.ToLowerInvariant(path1[c]) != char.ToLowerInvariant(path2[c]))
        {
            break;
        }

        if (path1[c] == '\\')
        {
            d = c;
        }

        c++;
    }

    if (c == 0)
    {
        return path2;
    }

    if (c == path1.Length && c == path2.Length)
    {
        return string.Empty;
    }


    System.Text.StringBuilder builder = new System.Text.StringBuilder();

    while (c < path1.Length)
    {
        if (path1[c] == '\\')
        {
            builder.Append(@"..\");
        }
        c++;
    }

    if (builder.Length == 0 && path2.Length - 1 == d)
    {
        return @".\";
    }

    return builder.ToString() + path2.Substring(d + 1);
}

Очакването за входовете изглежда е, че ако който и да е път представлява директория, той трябва да има обратна наклонена черта в края. Очевидно пътеките също трябва да са различни от нула.

Ето някои примерни входове и изходи... вижте дали отговаря на вашите нужди.

Path1                   Path2               Output
C:\test\path1\path2\    C:\test\            ..\..\
C:\test\path1\file      C:\test\            ..\
C:\test\path1\path2\    C:\                 ..\..\..\
C:\test\path1\path2\    D:\                 D:\
C:\test\path1\path2\    C:\test\path1\pathA ..\pathA
C:\test\                C:\test\    
C:\test\                C:\test\file        file
C:\test\file            C:\test\            .\
C:\test\path #1!\path2\ C:\test\            ..\..\
person Michael Petito    schedule 05.06.2011
comment
да, завършващата обратна наклонена черта е доста присъща, ако се замислите - алгото всъщност няма достъп до файловата система, нали? - person Eamon Nerbonne; 05.06.2011
comment
Не ми е съвсем удобно да вдигам това чрез рефлектор - не съм адвокат по авторски права и кой знае какво е ОК... - person Eamon Nerbonne; 05.06.2011
comment
Между другото, благодаря за усилията, със сигурност е интересен подход! - person Eamon Nerbonne; 05.06.2011
comment
...и това показва, че Uri не прави никакъв вид нормализиране, което тук е малко жалко; напр. сравняването на C:\test\path1\path2` to C:\test\\path1\pathA` не прави това, което трябва. От друга страна, C:\test\xy\..\path1\pathA работи с MakeRelativeUri по-горе, но не и тук... - person Eamon Nerbonne; 05.06.2011