给定完整路径,检查路径是否是某个其他路径的子目录,否则

and*_*ree 27 .net c# directory

我有2个字符串--dir1和dir2,我需要检查一个是否是其他的子目录.我尝试使用Contains方法:

dir1.contains(dir2);
Run Code Online (Sandbox Code Playgroud)

但是如果目录具有相似的名称,例如 - c:\abc并且c:\abc1不是子目录,则返回true也返回true.肯定有更好的办法.

Bro*_*ass 28

DirectoryInfo di1 = new DirectoryInfo(dir1);
DirectoryInfo di2 = new DirectoryInfo(dir2);
bool isParent = di2.Parent.FullName == di1.FullName;
Run Code Online (Sandbox Code Playgroud)

或者在循环中允许嵌套的子目录,即C:\ foo\bar\bazC:\ foo的子目录:

DirectoryInfo di1 = new DirectoryInfo(dir1);
DirectoryInfo di2 = new DirectoryInfo(dir2);
bool isParent = false;
while (di2.Parent != null)
{
    if (di2.Parent.FullName == di1.FullName)
    {
        isParent = true;
        break;
    }
    else di2 = di2.Parent;
}
Run Code Online (Sandbox Code Playgroud)

  • 仅当目录缺少最终斜杠时才有效.请参阅[为什么这个DirectoryInfo比较不起作用?](http://stackoverflow.com/questions/3155034) (3认同)

ang*_*sen 24

  • 不区分大小写
  • 容忍混合\/文件夹分隔符
  • 容忍..\路径
  • 避免匹配部分文件夹名称(c:\foobar不是子路径c:\foo)

注意:这仅匹配路径字符串,不适用于文件系统中的符号链接和其他类型的链接.

码:

public static class StringExtensions
{
    /// <summary>
    /// Returns true if <paramref name="path"/> starts with the path <paramref name="baseDirPath"/>.
    /// The comparison is case-insensitive, handles / and \ slashes as folder separators and
    /// only matches if the base dir folder name is matched exactly ("c:\foobar\file.txt" is not a sub path of "c:\foo").
    /// </summary>
    public static bool IsSubPathOf(this string path, string baseDirPath)
    {
        string normalizedPath = Path.GetFullPath(path.Replace('/', '\\')
            .WithEnding("\\"));

        string normalizedBaseDirPath = Path.GetFullPath(baseDirPath.Replace('/', '\\')
            .WithEnding("\\"));

        return normalizedPath.StartsWith(normalizedBaseDirPath, StringComparison.OrdinalIgnoreCase);
    }

    /// <summary>
    /// Returns <paramref name="str"/> with the minimal concatenation of <paramref name="ending"/> (starting from end) that
    /// results in satisfying .EndsWith(ending).
    /// </summary>
    /// <example>"hel".WithEnding("llo") returns "hello", which is the result of "hel" + "lo".</example>
    public static string WithEnding([CanBeNull] this string str, string ending)
    {
        if (str == null)
            return ending;

        string result = str;

        // Right() is 1-indexed, so include these cases
        // * Append no characters
        // * Append up to N characters, where N is ending length
        for (int i = 0; i <= ending.Length; i++)
        {
            string tmp = result + ending.Right(i);
            if (tmp.EndsWith(ending))
                return tmp;
        }

        return result;
    }

    /// <summary>Gets the rightmost <paramref name="length" /> characters from a string.</summary>
    /// <param name="value">The string to retrieve the substring from.</param>
    /// <param name="length">The number of characters to retrieve.</param>
    /// <returns>The substring.</returns>
    public static string Right([NotNull] this string value, int length)
    {
        if (value == null)
        {
            throw new ArgumentNullException("value");
        }
        if (length < 0)
        {
            throw new ArgumentOutOfRangeException("length", length, "Length is less than zero");
        }

        return (length < value.Length) ? value.Substring(value.Length - length) : value;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试用例(NUnit):

[TestFixture]
public class StringExtensionsTest
{
    [TestCase(@"c:\foo", @"c:", Result = true)]
    [TestCase(@"c:\foo", @"c:\", Result = true)]
    [TestCase(@"c:\foo", @"c:\foo", Result = true)]
    [TestCase(@"c:\foo", @"c:\foo\", Result = true)]
    [TestCase(@"c:\foo\", @"c:\foo", Result = true)]
    [TestCase(@"c:\foo\bar\", @"c:\foo\", Result = true)]
    [TestCase(@"c:\foo\bar", @"c:\foo\", Result = true)]
    [TestCase(@"c:\foo\a.txt", @"c:\foo", Result = true)]
    [TestCase(@"c:\FOO\a.txt", @"c:\foo", Result = true)]
    [TestCase(@"c:/foo/a.txt", @"c:\foo", Result = true)]
    [TestCase(@"c:\foobar", @"c:\foo", Result = false)]
    [TestCase(@"c:\foobar\a.txt", @"c:\foo", Result = false)]
    [TestCase(@"c:\foobar\a.txt", @"c:\foo\", Result = false)]
    [TestCase(@"c:\foo\a.txt", @"c:\foobar", Result = false)]
    [TestCase(@"c:\foo\a.txt", @"c:\foobar\", Result = false)]
    [TestCase(@"c:\foo\..\bar\baz", @"c:\foo", Result = false)]
    [TestCase(@"c:\foo\..\bar\baz", @"c:\bar", Result = true)]
    [TestCase(@"c:\foo\..\bar\baz", @"c:\barr", Result = false)]
    public bool IsSubPathOfTest(string path, string baseDirPath)
    {
        return path.IsSubPathOf(baseDirPath);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

  • 2015-08-18:修复部分文件夹名称的错误匹配.添加测试用例.
  • 2015-09-02:支持..\路径,添加缺失的代码
  • 2017-09-06:在符号链接上添加注释.

  • 值得注意的是,“[CanBeNull]”和“[NotNull]”注释是“JetBrains.Annotations”nuget 包的一部分。在这里找到它们:[JetBrains.Annotations](https://www.nuget.org/packages/JetBrains.Annotations/)。 (2认同)

Goo*_*ide 8

从 netstandard2.1 开始,终于有了一种几乎方便且与平台无关的方法来检查这一点:Path.GetRelativePath()

var relPath = Path.GetRelativePath(
    basePath.Replace('\\', '/'),
    subPath.Replace('\\', '/'));
var isSubPath =
    rel != "." && rel != ".."
    && !rel.StartsWith("../")
    && !Path.IsPathRooted(rel);
Run Code Online (Sandbox Code Playgroud)

subPathbasePath必须是绝对路径。

便捷扩展功能:

public static bool IsSubPathOf(this string subPath, string basePath) {
    var rel = Path.GetRelativePath(
        basePath.Replace('\\', '/'),
        subPath.Replace('\\', '/'));
    return rel != "."
        && rel != ".."
        && !rel.StartsWith("../")
        && !Path.IsPathRooted(rel);
}
Run Code Online (Sandbox Code Playgroud)

.NET 摆弄一些测试用例:https://dotnetfiddle.net/di4ze6


And*_*per 5

尝试:

dir1.contains(dir2+"\\");
Run Code Online (Sandbox Code Playgroud)