How to ensure there is trailing directory separator in paths?

.net, c#, path

Solution

It's like that, just keep your hack.

In plain Win32 there is an helper function PathAddBackslash for that. Just be consistent with directory separator: check `Path.DirectorySeparatorChar` and `Path.AltDirectorySeparatorChar` instead of hard-code `\`.

UPDATE: if you're targeting any recent.NET version (Core 3.0 and above) then you could use some newer functions:

string PathAddDirectorySeparator(string path)
{
    if (path is null)
        throw new ArgumentNullException(nameof(path));

    path = path.TrimEnd();

    if (Path.EndsInDirectorySeparator(path))
        return path;

    return path + GetDirectorySeparatorUsedInPath();

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

If you decide you do not want to support `Path.AltDirectorySeparatorChar` and you do not mind the extra string allocation then consider using `Path.TrimEndingDirectorySeparator(path)` instead of simply `path.TrimEnd('\\')`.

Original answer: something like this (please note there is not a serious error checking):

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's unusual but it may happen. If it's 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's just a directory name). In this case I
    // default to normal as users expect.
    return path + separator1;
}

Why so much code? Primary because if user enter `/windows/system32` you don't want to get `/windows/system32\` but `/windows/system32/`, devil is in the details...

To put everything together in a nicer self-explicative form:

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

    path = path.TrimEnd();

    if (PathEndsWithDirectorySeparator())
        return path;

    return path + GetDirectorySeparatorUsedInPath();

    bool PathEndsWithDirectorySeparator()
    {
        if (path.Length == 0)
            return false;

        char lastChar = path[path.Length - 1];
        return lastChar == Path.DirectorySeparatorChar
            || lastChar == Path.AltDirectorySeparatorChar;
    }

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

URI format `file://` is not handled even if it may seem so. The right thing is again to do what the other .NET I/O functions do: do not handle this format (and possibly throw an exception).

As alternative you're always able to import Win32 function:

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

Problem

I'm having an issue with `AppDomain.CurrentDomain.BaseDirectory`. Sometimes the path ends with '', sometimes it doesn't and I can't find a reason for this. It would be fine if I was using `Path.Combine` but I want to do `Directory.GetParent` and it yields different results. My current solution is: ``` var baseDir = AppDomain.CurrentDomain.BaseDirectory; if (!baseDir.EndsWith("\\")) baseDir += "\\"; ``` Is there another way to get the parent directory of the application?

Original source