如何检查目录 1 是否是 dir2 的子目录,反之亦然

发布于 2024-09-14 19:06:43 字数 168 浏览 9 评论 0原文

有什么简单的方法可以检查目录 1 是否是目录 2 的子目录,反之亦然?

我检查了 Path 和 DirectoryInfo 帮助程序类,但发现没有系统就绪的函数。我以为它会在那里的某个地方。

你们知道在哪里可以找到这个吗?

我尝试自己写一张支票,但它比我开始时预期的要复杂。

What is an easy way to check if directory 1 is a subdirectory of directory 2 and vice versa?

I checked the Path and DirectoryInfo helperclasses but found no system-ready function for this. I thought it would be in there somewhere.

Do you guys have an idea where to find this?

I tried writing a check myself, but it's more complicated than I had anticipated when I started.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

瞄了个咪的 2024-09-21 19:06:43

为了回答问题的第一部分:“dir1 是 dir2 的子目录吗?”,此代码应该有效:

public bool IsSubfolder(string parentPath, string childPath)
{
    var parentUri = new Uri(parentPath);
    var childUri = new DirectoryInfo(childPath).Parent;
    while (childUri != null)
    {
        if(new Uri(childUri.FullName) == parentUri)
        {
            return true;
        }
        childUri = childUri.Parent;
    }
    return false;
}

URI(至少在 Windows 上,在 Mono/Linux 上可能有所不同) ) 不区分大小写。如果区分大小写很重要,请改用 Uri 上的 Compare 方法。

In response to the first part of the question: "Is dir1 a sub-directory of dir2?", this code should work:

public bool IsSubfolder(string parentPath, string childPath)
{
    var parentUri = new Uri(parentPath);
    var childUri = new DirectoryInfo(childPath).Parent;
    while (childUri != null)
    {
        if(new Uri(childUri.FullName) == parentUri)
        {
            return true;
        }
        childUri = childUri.Parent;
    }
    return false;
}

The URIs (on Windows at least, might be different on Mono/Linux) are case-insensitive. If case sensitivity is important, use the Compare method on Uri instead.

病毒体 2024-09-21 19:06:43

这是使用 Uri 类的更简单的方法:

var parentUri = new Uri(parentPath);
var childUri = new Uri(childPath);
if (parentUri != childUri && parentUri.IsBaseOf(childUri))
{
   //dowork
}

Here's a simpler way to do it using the Uri class:

var parentUri = new Uri(parentPath);
var childUri = new Uri(childPath);
if (parentUri != childUri && parentUri.IsBaseOf(childUri))
{
   //dowork
}
殊姿 2024-09-21 19:06:43

请参阅此处的原始答案: https://stackoverflow.com/a/31941159/134761

  • 不区分
  • 大小写 容忍 的混合\/ 文件夹分隔符
  • 允许路径中的 ..\
  • 避免匹配部分文件夹名称(c:\foobar 不是子路径) of 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;
    }
}

测试用例 (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);
    }
}

更新 2015-08-18:修复部分文件夹名称匹配的错误。添加测试用例。

2016 年 1 月 29 日更新:原始问题链接 https://stackoverflow.com/a/31941159/134761

See original answer here: https://stackoverflow.com/a/31941159/134761

  • Case insensitive
  • Tolerates mix of \ and / folder delimiters
  • Tolerates ..\ in path
  • Avoids matching on partial folder names (c:\foobar not a subpath of c:\foo)

Code:

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

Test cases (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);
    }
}

Update 2015-08-18: Fix bug matching on partial folder names. Add test cases.

Update 2016-01-29: Link to original question https://stackoverflow.com/a/31941159/134761

坚持沉默 2024-09-21 19:06:43

DirectoryInfo 有一个属性 Parent,它也是 DirectoryInfo 类型。您可以使用它来确定您的目录是否是父目录的子目录。

DirectoryInfo has a property Parent which is also a DirectoryInfo type. You can use that to to determine if your directory is a subdirectory of a parent directory.

南薇 2024-09-21 19:06:43

如果第二个目录(d2)是 d1 的子文件夹,则其全名将包含第一个目录(d1)的全名。

这假设您正在使用有效的目录

if (d2.FullName.Contains(d1.FullName))
{
     //dowork
}

如果您需要检查映射驱动器,您可以尝试

    static void Main(string[] args)
    {
        if (GetUNCPath(d2.FullName).ToLower().Contains(GetUNCPath(d1.FullName).ToLower()))
        {
        }
    }

    [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int WNetGetConnection(
        [MarshalAs(UnmanagedType.LPTStr)] string localName,
        [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, ref int length);

    private static string GetUNCPath(string originalPath)
    {

        StringBuilder sb = new StringBuilder(512);
        int size = sb.Capacity;
        // look for the {LETTER}: combination ...
        if (originalPath.Length > 2 && originalPath[1] == ':')
        {
            // don't use char.IsLetter here - as that can be misleading
            // the only valid drive letters are a-z && A-Z.
            char c = originalPath[0];
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
            {
                int error = WNetGetConnection(originalPath.Substring(0, 2), sb, ref size);
                if (error == 0)
                {
                    DirectoryInfo dir = new DirectoryInfo(originalPath);
                    string path = Path.GetFullPath(originalPath).Substring(Path.GetPathRoot(originalPath).Length);
                    return Path.Combine(sb.ToString().TrimEnd(), path);
                }
            }
        }
        return originalPath;
    }

http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/6f79f2b3-d092 -431f-bc28-d15d93cf5d09

The second directories(d2) full name will contain the full name of the first directory(d1) if it is a sub-folder of d1.

This assumes that you are using valid directories

if (d2.FullName.Contains(d1.FullName))
{
     //dowork
}

If you need to check for mapped drives you could try

    static void Main(string[] args)
    {
        if (GetUNCPath(d2.FullName).ToLower().Contains(GetUNCPath(d1.FullName).ToLower()))
        {
        }
    }

    [DllImport("mpr.dll", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern int WNetGetConnection(
        [MarshalAs(UnmanagedType.LPTStr)] string localName,
        [MarshalAs(UnmanagedType.LPTStr)] StringBuilder remoteName, ref int length);

    private static string GetUNCPath(string originalPath)
    {

        StringBuilder sb = new StringBuilder(512);
        int size = sb.Capacity;
        // look for the {LETTER}: combination ...
        if (originalPath.Length > 2 && originalPath[1] == ':')
        {
            // don't use char.IsLetter here - as that can be misleading
            // the only valid drive letters are a-z && A-Z.
            char c = originalPath[0];
            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
            {
                int error = WNetGetConnection(originalPath.Substring(0, 2), sb, ref size);
                if (error == 0)
                {
                    DirectoryInfo dir = new DirectoryInfo(originalPath);
                    string path = Path.GetFullPath(originalPath).Substring(Path.GetPathRoot(originalPath).Length);
                    return Path.Combine(sb.ToString().TrimEnd(), path);
                }
            }
        }
        return originalPath;
    }

Code for mapped drive taken from http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/6f79f2b3-d092-431f-bc28-d15d93cf5d09

任性一次 2024-09-21 19:06:43

如果您有两个路径,请查看以下内容:

在 C# 中标准化目录名称

http://filedirectorypath.codeplex.com/ (我不知道它的质量)

并使用这个:

var ancestor = new DirectoryPathAbsolute(ancestorPath);
var child = new DirectoryPathAbsolute(childPath);

var res = child.IsChildDirectoryOf(ancestor); //I don't think it actually checks for case-sensitive filesystems

否则,如果您想知道某个目录是否作为路径中的子目录存在,请查看:

Directory.EnumerateDirectories

来自 .Net 4.0。示例:

path 是否包含以 Console 开头的目录:

//* is a wildcard. If you remove it, it search for directories called "Console"
var res = Directory.EnumerateDirectories(@path, "Console*", SearchOption.AllDirectories).Any();

If you have two path then look at this:

Normalize directory names in C#

http://filedirectorypath.codeplex.com/ (I don't know the quality of it)

And use this:

var ancestor = new DirectoryPathAbsolute(ancestorPath);
var child = new DirectoryPathAbsolute(childPath);

var res = child.IsChildDirectoryOf(ancestor); //I don't think it actually checks for case-sensitive filesystems

Otherwise, if you want to know whether a directory exists as a subdirectory in a path take a look on:

Directory.EnumerateDirectories

Came in .Net 4.0. Example:

Does path contain a directory starting with Console:

//* is a wildcard. If you remove it, it search for directories called "Console"
var res = Directory.EnumerateDirectories(@path, "Console*", SearchOption.AllDirectories).Any();
ゃ懵逼小萝莉 2024-09-21 19:06:43
public static bool IsSubfolder(DirectoryInfo parentPath, DirectoryInfo childPath)
{
return parentPath.FullName.StartsWith(childPath.FullName+Path.DirectorySeparatorChar);
}
public static bool IsSubfolder(DirectoryInfo parentPath, DirectoryInfo childPath)
{
return parentPath.FullName.StartsWith(childPath.FullName+Path.DirectorySeparatorChar);
}
涙—继续流 2024-09-21 19:06:43

您可以使用 Path.GetDirectoryName 方法 来获取父目录。它也适用于目录。

You can use Path.GetDirectoryName Method to get parent directory. It works for directories too.

谁许谁一生繁华 2024-09-21 19:06:43

angularsen的答案中编写的优秀测试用例的帮助下,我在.NET Core 3.1 for Windows上编写了以下更简单的扩展方法:

public static bool IsSubPathOf(this string dirPath, string baseDirPath, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
{
    dirPath = dirPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
    if (!dirPath.EndsWith(Path.DirectorySeparatorChar))
    {
      dirPath += Path.DirectorySeparatorChar;
    }
  
    baseDirPath = baseDirPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
    if (!baseDirPath.EndsWith(Path.DirectorySeparatorChar))
    {
      baseDirPath += Path.DirectorySeparatorChar;
    }

    string dirPathUri = new Uri(dirPath).LocalPath;
    string baseDirUri = new Uri(baseDirPath).LocalPath;

    return dirPathUri.Contains(baseDirUri, comparisonType);
}

With help from the great test cases written in angularsen's answer, I wrote the following simpler extension method on .NET Core 3.1 for Windows:

public static bool IsSubPathOf(this string dirPath, string baseDirPath, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
{
    dirPath = dirPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
    if (!dirPath.EndsWith(Path.DirectorySeparatorChar))
    {
      dirPath += Path.DirectorySeparatorChar;
    }
  
    baseDirPath = baseDirPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
    if (!baseDirPath.EndsWith(Path.DirectorySeparatorChar))
    {
      baseDirPath += Path.DirectorySeparatorChar;
    }

    string dirPathUri = new Uri(dirPath).LocalPath;
    string baseDirUri = new Uri(baseDirPath).LocalPath;

    return dirPathUri.Contains(baseDirUri, comparisonType);
}

这就是我得到的,在首先验证两个目录路径字符串是某种东西并且采用路径格式后我知道一些: shouldnotbechilddirpath.ToUpper().StartsWith(maybeparentdirpath.ToUpper())

确保如果您可能在区分大小写的文件系统中工作,请取出 ToUppers() 。

this is what I got, after first verifying that the two directory path strings are something and in a path format I know something about: shouldnotbechilddirpath.ToUpper().StartsWith(maybeparentdirpath.ToUpper())

Be sure to take out the ToUppers() if you are maybe working in a case sensitive file system.

临走之时 2024-09-21 19:06:43

您可以将directory2 与directory1 的父属性<进行比较/code>在这两种情况下使用 DirectoryInfo 时。

DirectoryInfo d1 = new DirectoryInfo(@"C:\Program Files\MyApp");
DirectoryInfo d2 = new DirectoryInfo(@"C:\Program Files\MyApp\Images");

if(d2.Parent.FullName == d1.FullName)
{
    Console.WriteLine ("Sub directory");
}

You can compare directory2 to directory1's Parent property when using a DirectoryInfo in both cases.

DirectoryInfo d1 = new DirectoryInfo(@"C:\Program Files\MyApp");
DirectoryInfo d2 = new DirectoryInfo(@"C:\Program Files\MyApp\Images");

if(d2.Parent.FullName == d1.FullName)
{
    Console.WriteLine ("Sub directory");
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文