Как извлечь имя каждой папки из пути?

Мой путь - \\server\folderName1\another name\something\another folder\

Как мне извлечь каждое имя папки в строку, если я не знаю, сколько папок находится в пути, и я не знаю имена папок?

Большое спасибо

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
71
0
114 032
16

Ответы 16

Быстрый ответ - использовать метод .Split ('\\').

Будьте осторожны, если вы хотите собрать массив обратно вместе с Path.Combine, если у вас была буква диска в начале пути - это будет снова вместе как c:server\folderName1....

Ben 09.06.2014 15:55

Может быть, вызвать Directory.GetParent в цикле? Это если вам нужен полный путь к каждому каталогу, а не только имена каталогов.

string mypath = @"..\folder1\folder2\folder2";
string[] directories = mypath.Split(Path.DirectorySeparatorChar);

Редактировать: Это возвращает каждую отдельную папку в массиве каталогов. Вы можете получить количество возвращенных папок следующим образом:

int folderCount = directories.Length;

Я добавил небольшое улучшение (где-то в этом посте), но я также отметил это как правильное. Отлично сработано!

granadaCoder 31.08.2011 00:51

Обратите внимание, что есть Path.AltDirectorySeparatorChar, который, возможно, также придется обработать. (например, через mypath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });)

Simon Opelt 18.02.2013 16:05

Это полностью разрушено на пути вроде \\ticows01\c$\AgArmourFTP. Извините, но подход слишком упрощен.

toddmo 16.09.2016 23:09

Или, если вам нужно что-то сделать с каждой папкой, взгляните на класс System.IO.DirectoryInfo. У него также есть свойство Parent, которое позволяет переходить к родительскому каталогу.

Путь к файлу можно представить несколькими способами. Вы должны использовать класс System.IO.Path для получения разделителей для ОС, поскольку он может различаться в UNIX и Windows. Кроме того, большинство (или все, если я не ошибаюсь) .NET-библиотек принимают в качестве разделителя пути либо '\', либо '/', независимо от ОС. По этой причине я бы использовал класс Path для разделения ваших путей. Попробуйте что-нибудь вроде следующего:

string originalPath = "\\server\\folderName1\\another\ name\\something\\another folder\\";
string[] filesArray = originalPath.Split(Path.AltDirectorySeparatorChar,
                              Path.DirectorySeparatorChar);

Это должно работать независимо от количества папок или имен.

Это хорошо в общем случае:

yourPath.Split(@"/", StringSplitOptions.RemoveEmptyEntries)

В возвращаемом массиве нет пустого элемента, если сам путь заканчивается (обратной) косой чертой (например, "\ foo \ bar \"). Однако вы должны быть уверены, что yourPath действительно является каталогом, а не файлом. Вы можете узнать, что это такое, и компенсировать, если это такой файл:

if (Directory.Exists(yourPath)) {
  var entries = yourPath.Split(@"/", StringSplitOptions.RemoveEmptyEntries);
}
else if (File.Exists(yourPath)) {
  var entries = Path.GetDirectoryName(yourPath).Split(
                    @"/", StringSplitOptions.RemoveEmptyEntries);
}
else {
  // error handling
}

Я считаю, что это охватывает все основы, не будучи слишком педантичным. Он вернет string[], который вы можете перебирать с foreach, чтобы получить каждый каталог по очереди.

Если вы хотите использовать константы вместо волшебной строки @"/", вам нужно использовать

var separators = new char[] {
  Path.DirectorySeparatorChar,  
  Path.AltDirectorySeparatorChar  
};

а затем используйте separators вместо @"/" в приведенном выше коде. Лично я считаю это слишком многословным и, скорее всего, не буду этого делать.

Это не работает в C# 6 со следующими ошибками: path.Split(@"/", StringSplitOptions.RemoveEmptyEntries); (1,12): error CS1503: Argument 1: cannot convert from 'string' to 'char' (1,19): error CS1503: Argument 2: cannot convert from 'System.StringSplitOptions' to 'char'. Создание нового char [] с разделителем в нем действительно работает: path.Split(new char[] { Path.DirectorySeparatorChar }, options: StringSplitOptions.RemoveEmptyEntries); действительно работает.

Thoughtful Dragon 01.03.2017 23:08

Я написал следующий метод, который мне подходит.

protected bool isDirectoryFound(string path, string pattern)
    {
        bool success = false;

        DirectoryInfo directories = new DirectoryInfo(@path);
        DirectoryInfo[] folderList = directories.GetDirectories();

        Regex rx = new Regex(pattern);

        foreach (DirectoryInfo di in folderList)
        {
            if (rx.IsMatch(di.Name))
            {
                success = true;
                break;
            }
        }

        return success;
    }

Строки, наиболее подходящие для вашего вопроса:

DirectoryInfo каталогов = новый DirectoryInfo (@path); DirectoryInfo [] folderList = каталоги.GetDirectories ();

DirectoryInfo objDir = new DirectoryInfo(direcotryPath);
DirectoryInfo [] directoryNames =  objDir.GetDirectories("*.*", SearchOption.AllDirectories);

Это даст вам все каталоги и подкаталоги.

Если они существуют, то есть.

stijn 29.03.2020 14:44

Я добавляю ответ Мэтта Брунелла.

            string[] directories = myStringWithLotsOfFolders.Split(Path.DirectorySeparatorChar);

            string previousEntry = string.Empty;
            if (null != directories)
            {
                foreach (string direc in directories)
                {
                    string newEntry = previousEntry + Path.DirectorySeparatorChar + direc;
                    if (!string.IsNullOrEmpty(newEntry))
                    {
                        if (!newEntry.Equals(Convert.ToString(Path.DirectorySeparatorChar), StringComparison.OrdinalIgnoreCase))
                        {
                            Console.WriteLine(newEntry);
                            previousEntry = newEntry;
                        }
                    }
                }
            }

Это должно дать вам:

"\ сервер"

"\ сервер \ имя_папки1"

"\ server \ folderName1 \ другое имя"

"\ server \ folderName1 \ другое имя \ что-то"

"\ server \ folderName1 \ другое имя \ something \ другая папка \"

(или отсортируйте полученную коллекцию по строке. Длина каждого значения.

Поймите, это старый пост, но я наткнулся на него, глядя - в конце концов, я решил использовать функцию ниже, поскольку она сортировала то, что я делал в то время, лучше, чем что-либо из вышеперечисленного:

private static List<DirectoryInfo> SplitDirectory(DirectoryInfo parent)
{
    if (parent == null) return null;
    var rtn = new List<DirectoryInfo>();
    var di = parent;

    while (di.Name != di.Root.Name)
    {
    rtn.Add(new DirectoryInfo(di));
    di = di.Parent;
    }
    rtn.Add(new DirectoryInfo(di.Root));

    rtn.Reverse();
    return rtn;
}
rtn.Add(new DirectoryInfo(di)); неправильный, должен быть rtn.Add(di);, а также заменить rtn.Add(new DirectoryInfo(di.Root)); на rtn.Add(di.Root);
Jaider 07.01.2014 23:25

Спасибо за этот пример. Хранение объектов DirectoryInfo вместо простых строк полезно, если в дальнейшем вам потребуется взаимодействовать с папками.

Louis 19.06.2014 22:51

Я реализовал более краткий метод ниже, вдохновленный вашим ответом.

K. R. 02.10.2015 18:55
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    /// <summary>
    /// Use to emulate the C lib function _splitpath()
    /// </summary>
    /// <param name = "path">The path to split</param>
    /// <param name = "rootpath">optional root if a relative path</param>
    /// <returns>the folders in the path. 
    ///     Item 0 is drive letter with ':' 
    ///     If path is UNC path then item 0 is "\\"
    /// </returns>
    /// <example>
    /// string p1 = @"c:\p1\p2\p3\p4";
    /// string[] ap1 = p1.SplitPath();
    /// // ap1 = {"c:", "p1", "p2", "p3", "p4"}
    /// string p2 = @"\\server\p2\p3\p4";
    /// string[] ap2 = p2.SplitPath();
    /// // ap2 = {@"\\", "server", "p2", "p3", "p4"}
    /// string p3 = @"..\p3\p4";
    /// string root3 = @"c:\p1\p2\";
    /// string[] ap3 = p1.SplitPath(root3);
    /// // ap3 = {"c:", "p1", "p3", "p4"}
    /// </example>
    public static string[] SplitPath(this string path, string rootpath = "")
    {
        string drive;
        string[] astr;
        path = Path.GetFullPath(Path.Combine(rootpath, path));
        if (path[1] == ':')
        {
            drive = path.Substring(0, 2);
            string newpath = path.Substring(2);
            astr = newpath.Split(new[] { Path.DirectorySeparatorChar }
                , StringSplitOptions.RemoveEmptyEntries);
        }
        else
        {
            drive = @"\\";
            astr = path.Split(new[] { Path.DirectorySeparatorChar }
                , StringSplitOptions.RemoveEmptyEntries);
        }
        string[] splitPath = new string[astr.Length + 1];
        splitPath[0] = drive;
        astr.CopyTo(splitPath, 1);
        return splitPath;
    }

Я вижу ваш методВолк5370 и поднимаю вас.

internal static List<DirectoryInfo> Split(this DirectoryInfo path)
{
    if (path == null) throw new ArgumentNullException("path");
    var ret = new List<DirectoryInfo>();
    if (path.Parent != null) ret.AddRange(Split(path.Parent));
    ret.Add(path);
    return ret;
}

На пути c:\folder1\folder2\folder3 это возвращает

c:\

c:\folder1

c:\folder1\folder2

c:\folder1\folder2\folder3

В этой последовательности

ИЛИ ЖЕ

internal static List<string> Split(this DirectoryInfo path)
{
    if (path == null) throw new ArgumentNullException("path");
    var ret = new List<string>();
    if (path.Parent != null) ret.AddRange(Split(path.Parent));
    ret.Add(path.Name);
    return ret;
}

вернусь

c:\

folder1

folder2

folder3

public static IEnumerable<string> Split(this DirectoryInfo path)
{
    if (path == null) 
        throw new ArgumentNullException("path");
    if (path.Parent != null)
        foreach(var d in Split(path.Parent))
            yield return d;
    yield return path.Name;
}

Мне нравится ваш подход, но я сделал более простую реализацию без рекурсии. +1

Roland 26.09.2019 19:28

Вот модификация ответа Вольфа, которая исключает корень и исправляет, казалось бы, пару ошибок. Я использовал его для создания панировочных сухарей, и я не хотел, чтобы корень отображался.

это расширение типа DirectoryInfo.

public static List<DirectoryInfo> PathParts(this DirectoryInfo source, string rootPath)
{
  if (source == null) return null;
  DirectoryInfo root = new DirectoryInfo(rootPath);
  var pathParts = new List<DirectoryInfo>();
  var di = source;

  while (di != null && di.FullName != root.FullName)
  {
    pathParts.Add(di);
    di = di.Parent;
  }

  pathParts.Reverse();
  return pathParts;
}

Я просто закодировал это, так как не нашел уже встроенных в C#.

/// <summary>
/// get the directory path segments.
/// </summary>
/// <param name = "directoryPath">the directory path.</param>
/// <returns>a IEnumerable<string> containing the get directory path segments.</returns>
public IEnumerable<string> GetDirectoryPathSegments(string directoryPath)
{
    if (string.IsNullOrEmpty(directoryPath))
    { throw new Exception($"Invalid Directory: {directoryPath ?? "null"}"); }

    var currentNode = new System.IO.DirectoryInfo(directoryPath);

    var targetRootNode = currentNode.Root;
    if (targetRootNode == null) return new string[] { currentNode.Name };
    var directorySegments = new List<string>();
    while (string.Compare(targetRootNode.FullName, currentNode.FullName, StringComparison.InvariantCultureIgnoreCase) != 0)
    {
        directorySegments.Insert(0, currentNode.Name);
        currentNode = currentNode.Parent;
    }
    directorySegments.Insert(0, currentNode.Name);
    return directorySegments;
}

На основе предыдущих ответов, но проще и без рекурсии. Кроме того, его не волнует, что такое символ разделения, поскольку Dir.Parent покрывает это:

    /// <summary>
    /// Split a directory in its components.
    /// Input e.g: a/b/c/d.
    /// Output: d, c, b, a.
    /// </summary>
    /// <param name = "Dir"></param>
    /// <returns></returns>
    public static IEnumerable<string> DirectorySplit(this DirectoryInfo Dir)
    {
        while (Dir != null)
        {
            yield return Dir.Name;
            Dir = Dir.Parent;
        }
    }

Либо вставьте это в класс static, чтобы создать хороший метод расширения, либо просто оставьте thisstatic).

Пример использования (как метод расширения) для доступа к частям пути по номеру:

    /// <summary>
    /// Return one part of the directory path.
    /// Path e.g.: a/b/c/d. PartNr=0 is a, Nr 2 = c.
    /// </summary>
    /// <param name = "Dir"></param>
    /// <param name = "PartNr"></param>
    /// <returns></returns>
    public static string DirectoryPart(this DirectoryInfo Dir, int PartNr)
    {
        string[] Parts = Dir.DirectorySplit().ToArray();
        int L = Parts.Length;
        return PartNr >= 0 && PartNr < L ? Parts[L - 1 - PartNr] : "";
    }

Оба вышеуказанных метода теперь находятся в моей личной библиотеке, отсюда и комментарии в формате xml. Пример использования:

    DirectoryInfo DI_Data = new DirectoryInfo(@"D:\Hunter\Data\2019\w38\abc\000.d");
    label_Year.Text = DI_Data.DirectoryPart(3); // --> 2019
    label_Entry.Text = DI_Data.DirectoryPart(6);// --> 000.d

Другие вопросы по теме