【问题标题】:How to ensure there is trailing directory separator in paths?如何确保路径中有尾随目录分隔符?
【发布时间】:2013-12-22 17:53:49
【问题描述】:

我遇到了AppDomain.CurrentDomain.BaseDirectory 的问题。

有时路径以 '' 结尾,有时不是,我找不到原因。

如果我使用Path.Combine 会很好,但我想使用Directory.GetParent,它会产生不同的结果。

我目前的解决方案是:

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

还有其他方法可以获取应用的父目录吗?

【问题讨论】:

    标签: c# .net path


    【解决方案1】:

    就是这样,保持你的技巧。

    plain Win32 中有一个帮助函数 PathAddBackslash 。只需与目录分隔符保持一致:检查Path.DirectorySeparatorCharPath.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'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;
    }
    

    为什么这么多代码?主要是因为如果用户输入/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()
        {
            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 格式file:// 不被处理,即使看起来是这样。 正确的事情是再次做其他 .NET I/O 函数所做的事情:不处理这种格式(并可能引发异常)。

    作为替代方案,您始终可以导入 Win32 函数:

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

    【讨论】:

    • 我不确定我是否会使用替代方案。虽然它很有趣,但开发人员不确定代码在做什么。
    • @pitermarx 实际上我们甚至不确定 FileCopy 的作用! system 函数 IMO 始终是一个不错的选择,至少它会为您处理任何更改(并且它将始终遵守其约定:添加尾部反斜杠)。当然,它们并不总是完美的解决方案......
    • @AdrianoRepetti:Windows 允许在文件/目录名称中使用前导空格,因此 Trim() 调用没有好处。 (它可能还允许尾随空格,但至少 cmd.exe 似乎不支持它们,而且我还没有做进一步的测试,所以我不能确定。)就我个人而言,我只是完全删除了 Trim 调用。毕竟,“修复”损坏的路径不是功能的责任。此外,我将更改“添加哪个”逻辑以仅复制字符串中的最后一个分隔符(我已经看到 file:// 路径在字符串的其余部分中使用了反斜杠)。
    • @PaulGroke 你对前导空格是正确的(更新答案)。大多数 .NET I/O 函数都不允许使用 URI 格式,那么这不是问题(使用 file:// 处理 URI 时,您必须自己提取路径)。
    • 您的第一个版本不是将file://drive:\path\filename.ext 转换为file://drive:\path\filename.ext/,而第二个版本创建了`file://drive:\path\filename.ext`?即,如果有混合分隔符,第一个版本不喜欢替代分隔符,而第二个版本更喜欢标准分隔符吗?
    【解决方案2】:

    您可以使用TrimEnd 轻松确保您想要的行为:

    var baseDir = AppDomain.CurrentDomain.BaseDirectory
                      .TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar;
    

    为了获得最佳效率(通过避免额外分配),请在进行更改之前检查字符串是否以 \ 结尾,因为您并不总是需要:

    const string sepChar = Path.DirectorySeparatorChar.ToString();
    const string altChar = Path.AltDirectorySeparatorChar.ToString();
    
    var baseDir = AppDomain.CurrentDomain.BaseDirectory;
    if (!baseDir.EndsWith(sepChar) && !baseDir.EndsWith(altChar))
    {
        baseDir += sepChar;
    }
    

    【讨论】:

    • 要使其跨平台,您可以将 "\\" 替换为 Path.DirectorySeparatorChar
    • @Rots:TrimEnd 调用也应该包括 AltDirectorySeparatorChar
    • 使用三元运算符的更简洁的语法:var baseDir = AppDomain.CurrentDomain.BaseDirectory;baseDir = baseDir.EndsWith(Path.DirectorySeparatorChar.ToString()) ? baseDir : baseDir + Path.DirectorySeparatorChar;
    【解决方案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】:

      为了获得跨平台支持,可以使用这个 sn-p:

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

      【讨论】:

        【解决方案5】:

        你可以简单地使用 C# Path 库,有一个名为 TrimEndingDirectorySeparator 的方法,给出你的方法的路径,如果任何目录分隔符存在于你的路径末尾将修剪,无论您的路径是虚拟的还是物理的,然后如果必须使用 C# $ 键,而不是使用旧方法使用 String.Format 制作路径字符串路径中的 / 分隔符只需将 $ 和 @ 混合在一起,如下例所示。

        var baseDir = AppDomain.CurrentDomain.BaseDirectory;
        
        string finalPath = $@"{Path.TrimEndingDirectorySeparator(baseDir)}/"
        

        【讨论】:

        • 如果您知道路径应该采用什么格式,即如果您知道斜线需要是哪个方向,那么很好的简单解决方案 - 其他一些解决方案更长,但在这方面提供了更多的灵活性/适应性看待。也只是为了让其他人清楚,这仅适用于 .NET Core 3.0 和 .NET 5.0 及更高版本docs.microsoft.com/en-us/dotnet/api/…
        【解决方案6】:

        从 .NET Core 3.0 开始,可以使用Path.EndsInDirectorySeparator()

        string baseDir = AppDomain.CurrentDomain.BaseDirectory;
        
        if (!Path.EndsInDirectorySeparator(baseDir))
        {
            baseDir += Path.DirectorySeparatorChar;
        }
        

        对于Unix,它检查最后一个char 是否为'/'

        对于Windows,它检查最后一个char 是文字'\' 还是'/'

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-23
          • 1970-01-01
          • 2017-10-12
          • 1970-01-01
          • 2011-06-10
          • 1970-01-01
          • 2014-01-16
          • 1970-01-01
          相关资源
          最近更新 更多