Подтвердить что ты не робот

Как убедиться, что в пути есть трейлинг-сепаратор каталога?

У меня проблема с AppDomain.CurrentDomain.BaseDirectory.

Иногда путь заканчивается на "\", а в других случаях - нет. Я не могу найти причину этого.

Было бы хорошо, если бы я использовал Path.Combine, но я хочу сделать Directory.GetParent, и он даст разные результаты.

Вы нашли эту проблему?

Можно ли поступить иначе, чтобы получить родительский каталог приложения?

Мой текущий взлом:

var baseDir = AppDomain.CurrentDomain.BaseDirectory;
if (!baseDir.EndsWith("\\")) baseDir += "\\";
4b9b3361

Ответ 1

Вот так, просто держи свой хак.

В простой Win32 для этого есть вспомогательная функция PathAddBackslash. Просто совместите с разделителем каталогов: проверьте Path.DirectorySeparatorChar и Path.AltDirectorySeparatorChar вместо жесткого кода \.

Что-то вроде этого (обратите внимание, что серьезной проверки ошибок нет):

string PathAddBackslash(string path)
{
    // They're always one character but EndsWith is shorter than
    // array style access to last path character. Change this
    // if performance are a (measured) issue.
    string separator1 = Path.DirectorySeparatorChar.ToString();
    string separator2 = Path.AltDirectorySeparatorChar.ToString();

    // Trailing white spaces are always ignored but folders may have
    // leading spaces. It unusual but it may happen. If it an issue
    // then just replace TrimEnd() with Trim(). Tnx Paul Groke to point this out.
    path = path.TrimEnd();

    // Argument is always a directory name then if there is one
    // of allowed separators then I have nothing to do.
    if (path.EndsWith(separator1) || path.EndsWith(separator2))
        return path;

    // If there is the "alt" separator then I add a trailing one.
    // Note that URI format (file://drive:\path\filename.ext) is
    // not supported in most .NET I/O functions then we don't support it
    // here too. If you have to then simply revert this check:
    // if (path.Contains(separator1))
    //     return path + separator1;
    //
    // return path + separator2;
    if (path.Contains(separator2))
        return path + separator2;

    // If there is not an "alt" separator I add a "normal" one.
    // It means path may be with normal one or it has not any separator
    // (for example if it just a directory name). In this case I
    // default to normal as users expect.
    return path + separator1;
}

Почему так много кода? Первичный, потому что если пользователь вводит /windows/system32, вы не хотите получать /windows/system32\, но /windows/system32/, дьявол находится в деталях...

Чтобы собрать все вместе в более удобной самоочевидной форме:

string PathAddBackslash(string path)
{
    if (path == null)
        throw new ArgumentNullException(nameof(path));

    path = path.TrimEnd();

    if (PathEndsWithDirectorySeparator())
        return path;

    return path + GetDirectorySeparatorUsedInPath();

    bool PathEndsWithDirectorySeparator()
    {
        char lastChar = path.Last();
        return lastChar == Path.DirectorySeparatorChar
            || lastChar == Path.AltDirectorySeparatorChar;
    }

    char GetDirectorySeparatorUsedInPath()
    {
        if (path.Contains(Path.DirectorySeparatorChar))
            return Path.DirectorySeparatorChar;

        return Path.AltDirectorySeparatorChar;
    }
}

В этом втором примере формат URI file://, по-видимому, корректно обрабатывается, но не обманывается внешностью: он не (например, с ошибкой file://path). Правильная вещь - снова сделать то, что делают другие функции .NET I/O: не обрабатывать этот формат (и, возможно, исключать).

В качестве альтернативы вы всегда можете импортировать функцию Win32:

[DllImport("shlwapi.dll", 
 EntryPoint = "PathAddBackslashW",
 SetLastError = True,
 CharSet = CharSet.Unicode)]
static extern IntPtr PathAddBackslash(
    [MarshalAs(UnmanagedType.LPTStr)]StringBuilder lpszPath);

Ответ 2

Вы можете легко обеспечить желаемое поведение, используя TrimEnd:

var baseDir = AppDomain.CurrentDomain.BaseDirectory.TrimEnd('\\') + "\\";

Чтобы быть оптимально эффективным (избегая дополнительных распределений), убедитесь, что строка не заканчивается символом \ перед внесением изменений, поскольку вам не всегда нужно:

var baseDir = AppDomain.CurrentDomain.BaseDirectory;
if (!baseDir.EndsWith("\\"))
{
    baseDir += "\\";
}

Ответ 3

Я часто использую

path = Path.Combine(path, "x");
path = path.Substring(0, path.Length - 1);

Или, если мне понадобилось это более одного или двух раз в одном проекте, я бы, вероятно, использовал вспомогательную функцию:

string EnsureTerminatingDirectorySeparator(string path)
{
    if (path == null)
        throw new ArgumentNullException("path");

    int length = path.Length;
    if (length == 0)
        return "." + Path.DirectorySeparatorChar;

    char lastChar = path[length - 1];
    if (lastChar == Path.DirectorySeparatorChar || lastChar == Path.AltDirectorySeparatorChar)
        return path;

    int lastSep = path.LastIndexOfAny(new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
    if (lastSep >= 0)
        return path + path[lastSep];
    else
        return path + Path.DirectorySeparatorChar;
}

Ответ 4

Чтобы получить поддержку кросс-платформы, вы можете использовать этот фрагмент:

using System.IO;

// Your input string.
string baseDir = AppDomain.CurrentDomain.BaseDirectory;

// Get the absolut path from it (in case ones input is a relative path).
string fullPath = Path.GetFullPath(baseDir);

// Check for ending slashes, remove them (if any)
// and add a cross platform slash at the end.
string result = fullPath
                    .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
                    + Path.DirectorySeparatorChar;

Как метод:

private static string GetFullPathWithEndingSlashes(string input)
{
    string fullPath = Path.GetFullPath(input);

    return fullPath
        .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
        + Path.DirectorySeparatorChar;
}

Или как метод расширения:

public static string GetFullPathWithEndingSlashes(this string input)
{
    return Path.GetFullPath(input)
        .TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)
        + Path.DirectorySeparatorChar;
}