Как проверить, является ли каталог 1 подкаталогом dir2 и наоборот

Что такое простой способ проверить, является ли каталог 1 подкаталогом каталога 2 и наоборот?

Я проверил helperclasses пути и DirectoryInfo, но не нашел для него никакой готовой для системы функции. Я думал, что это где-то там.

У вас есть идея, где это найти?

Я попытался написать чек сам, но это сложнее, чем я ожидал, когда начал.

Ответ 1

Вы можете сравнить каталог2 с каталогом Parent property при использовании 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");
}

Ответ 2

В ответ на первую часть вопроса: "Является ли 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) нечувствительны к регистру. Если важна чувствительность к регистру, используйте метод Compare на URI.

Ответ 3

Здесь более простой способ сделать это с помощью класса Uri:

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

Ответ 4

См. оригинальный ответ здесь: fooobar.com/questions/244691/...

  • Нечувствительность к регистру
  • Толерантное сочетание \ и / разделителей папок
  • Толеранты ..\ в пути
  • Предотвращает совпадение имен парных папок (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;
    }
}

Тестовые примеры (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-01-29: ссылка на исходный вопрос fooobar.com/questions/244691/...

Ответ 5

Если у вас есть два пути, посмотрите на это:

Нормализовать имена каталогов на С#

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();

Ответ 6

В DirectoryInfo есть свойство Parent, которое также является типом DirectoryInfo. Вы можете использовать это, чтобы определить, является ли ваш каталог подкаталогом родительского каталога.

Ответ 7

Полное имя второго каталога (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

Ответ 8

Вы можете использовать Path.GetDirectoryName Method для получения родительского каталога. Он также работает для каталогов.

Ответ 9

public static bool IsSubfolder(DirectoryInfo parentPath, DirectoryInfo childPath)
{
return parentPath.FullName.StartsWith(childPath.FullName+Path.DirectorySeparatorChar);
}

Ответ 10

это то, что я получил после первой проверки того, что две строки пути каталога - это что-то и в формате пути. Я кое-что знаю о: shouldnotbechilddirpath.ToUpper().StartsWith(maybeparentdirpath.ToUpper())

Обязательно выньте ToUppers(), если вы, возможно, работаете в файловой системе, чувствительной к регистру.