如何从路径中提取每个文件夹名称?


68

我的路是 \\server\folderName1\another name\something\another folder\

如果我不知道路径中有多少个文件夹并且不知道文件夹名称,如何将每个文件夹名称提取为字符串?

非常感谢

Answers:


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

编辑:这将返回目录数组中的每个单独的文件夹。您可以像这样获取返回的文件夹数:

int folderCount = directories.Length;

我添加了一个小的增强功能(在本文的某个地方),但我也将此标记为正确。打的好!
granadaCoder

19
请注意,可能还有一个Path.AltDirectorySeparatorChar可能也需要处理。(例如,通过mypath.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar });
Simon Opelt

14
这完全破坏了像这样的路径\\ticows01\c$\AgArmourFTP。抱歉,但是方法太简单了。
toddmo

31

在一般情况下这很好:

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);确实可行。
周到的龙

9

意识到这是一篇老文章,但是我发现它看起来很像-最终,我决定支持以下功能,因为它比当时的任何功能都更好地整理了我当时的工作:

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

谢谢这个例子。如果以后需要与文件夹进行交互,则存储DirectoryInfo对象而不是简单的字符串将很有用。
2014年

下面,根据您的回答,我实现了一种更简洁的方法。
KR 2015年

9

我看到您的方法 Wolf5370并抚养您。

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


5
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
我喜欢您的方法,但是我实现了一个更简单的实现,没有递归。+1
罗兰

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

3

快速的答案是使用.Split('\\')方法。


4
如果要把阵列放回Path.Combine原处,并且路径的开头有驱动器号,请当心-这将作为一起返回c:server\folderName1...
2014年


2

有几种方法可以表示文件路径。您应该使用System.IO.Path该类来获取操作系统的分隔符,因为UNIX和Windows之间的分隔符可能有所不同。此外,大多数(如果我没有记错的话,.NET库也是如此).NET库接受'\'或'/'作为路径分隔符,而不考虑OS。因此,我将使用Path类来分割路径。尝试如下操作:

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

无论文件夹的数量或名称如何,这都应该起作用。


2

受到早期答案的启发,但更简单,而且没有递归。同样,它也不关心分隔符号是什么,因为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类中以创建一个不错的扩展方法,或者仅忽略this(和static)。

通过数字访问路径部分的用法示例(作为扩展方法):

    /// <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

0

或者,如果您需要对每个文件夹进行操作,请查看System.IO.DirectoryInfo类。它还具有Parent属性,可让您导航到父目录。


0

我写了以下对我有用的方法。

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 = directory.GetDirectories();


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

这将为您提供所有目录和子目录。


如果存在,那就是。
stijn

0

我要补充马特·布鲁内尔(Matt Brunell)的答案。

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

这应该给您:

“\服务器”

“ \ server \ folderName1”

“ \ server \ folderName1 \另一个名称”

“ \ server \ folderName1 \另一个名称\某物”

“ \ server \ folderName1 \另一个名称\ something \另一个文件夹\”

(或按字符串的长度对结果集合进行排序。每个值的长度。


0

这是对Wolf答案的修改,它省略了根本原因并修复了似乎有几个错误的地方。我用它来生成面包屑,但我不想显示根。

这是该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;
}

0

我只是编写了此代码,因为我发现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;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.