2008-12-29 12 views
19

No sé si es legítimo en StackOverflow publicar su propia respuesta a una pregunta, pero vi que nadie ya lo había preguntado. Fui en busca de C# Glob y no encontré ninguna, así que escribí una que otros podrían encontrarle útil.Cómo implementar glob en C#

+0

Después de un poco de google-ling encontré lo que se supone que debe hacer glob. http://en.wikipedia.org/wiki/Glob_(programming) – tuinstoel

+0

Habría obtenido más puntos si no lo hubiera convertido en una wiki de la comunidad. :-) –

+0

¿Por qué habría conseguido más puntos? Soy nuevo aquí ... –

Respuesta

14
/// <summary> 
    /// return a list of files that matches some wildcard pattern, e.g. 
    /// C:\p4\software\dotnet\tools\*\*.sln to get all tool solution files 
    /// </summary> 
    /// <param name="glob">pattern to match</param> 
    /// <returns>all matching paths</returns> 
    public static IEnumerable<string> Glob(string glob) 
    { 
     foreach (string path in Glob(PathHead(glob) + DirSep, PathTail(glob))) 
      yield return path; 
    } 

    /// <summary> 
    /// uses 'head' and 'tail' -- 'head' has already been pattern-expanded 
    /// and 'tail' has not. 
    /// </summary> 
    /// <param name="head">wildcard-expanded</param> 
    /// <param name="tail">not yet wildcard-expanded</param> 
    /// <returns></returns> 
    public static IEnumerable<string> Glob(string head, string tail) 
    { 
     if (PathTail(tail) == tail) 
      foreach (string path in Directory.GetFiles(head, tail).OrderBy(s => s)) 
       yield return path; 
     else 
      foreach (string dir in Directory.GetDirectories(head, PathHead(tail)).OrderBy(s => s)) 
       foreach (string path in Glob(Path.Combine(head, dir), PathTail(tail))) 
        yield return path; 
    } 

    /// <summary> 
    /// shortcut 
    /// </summary> 
    static char DirSep = Path.DirectorySeparatorChar; 

    /// <summary> 
    /// return the first element of a file path 
    /// </summary> 
    /// <param name="path">file path</param> 
    /// <returns>first logical unit</returns> 
    static string PathHead(string path) 
    { 
     // handle case of \\share\vol\foo\bar -- return \\share\vol as 'head' 
     // because the dir stuff won't let you interrogate a server for its share list 
     // FIXME check behavior on Linux to see if this blows up -- I don't think so 
     if (path.StartsWith("" + DirSep + DirSep)) 
      return path.Substring(0, 2) + path.Substring(2).Split(DirSep)[0] + DirSep + path.Substring(2).Split(DirSep)[1]; 

     return path.Split(DirSep)[0]; 
    } 

    /// <summary> 
    /// return everything but the first element of a file path 
    /// e.g. PathTail("C:\TEMP\foo.txt") = "TEMP\foo.txt" 
    /// </summary> 
    /// <param name="path">file path</param> 
    /// <returns>all but the first logical unit</returns> 
    static string PathTail(string path) 
    { 
     if (!path.Contains(DirSep)) 
      return path; 

     return path.Substring(1 + PathHead(path).Length); 
    } 
+0

¿Error? Tuve que reemplazar "Path.Combine (head, dir)" por "dir" ya que Directory.GetDirectories ya devuelve la ruta completa. Esto causó un error con rutas como ".. \ SomeDir \ *. Dll" ya que ".. \" fueron duplicadas por Combine – jturcotte

+1

Esto no parece funcionar si pasas una cadena como '*' a la función 'Glob' . ¿Se están haciendo algunas suposiciones sobre el tipo de cadena comodín que puede manejar? ¿Un camino absoluto tal vez? – Ben

+0

El método 'Glob' divide el argumento en dos partes en un' DirSep'. El código falla si no hay 'Dirsep'. Agregar la siguiente instrucción al principio del método 'PathHead' parece funcionar:' if (! Path.Contains (DirSep)) {return ".";} '. – AdrianHHH

0

Puede utilizar el "dir" (también conocido como "Get-ChildItem") cmdlet de PowerShell desde C#.
(No estoy diciendo que si usted debe.)

Hay que añadir esta referencia al archivo de proyecto (".csproj" o " .vcproj") de forma manual:

<Reference Include="System.Management.Automation" /> 

Ver aquí para más detalles sobre cómo usar los cmdlets de C#: http://www.devx.com/tips/Tip/42716

aquí un programa de trabajo:

using System; 
using System.Collections.Generic; 

using System.Management.Automation; 
using System.Management.Automation.Runspaces; 
using System.Collections.ObjectModel; 

namespace CsWildcard { 
    class Program { 

     static IEnumerable<string> CmdletDirGlobbing(string basePath, string glob){ 
      Runspace runspace = RunspaceFactory.CreateRunspace(); 
      runspace.Open(); 

      // cd to basePath 
      if(basePath != null){ 
       Pipeline cdPipeline = runspace.CreatePipeline(); 
       Command cdCommand = new Command("cd"); 
       cdCommand.Parameters.Add("Path", basePath); 
       cdPipeline.Commands.Add(cdCommand); 
       cdPipeline.Invoke(); // run the cmdlet 
      } 

      // run the "dir" cmdlet (e.g. "dir C:\*\*\*.txt") 
      Pipeline dirPipeline = runspace.CreatePipeline(); 
      Command dirCommand = new Command("dir"); 
      dirCommand.Parameters.Add("Path", glob); 
      dirPipeline.Commands.Add(dirCommand); 

      Collection<PSObject> dirOutput = dirPipeline.Invoke(); 

      // for each found file 
      foreach (PSObject psObject in dirOutput) { 

       PSMemberInfoCollection<PSPropertyInfo> a = psObject.Properties; 
       // look for the full path ("FullName") 
       foreach (PSPropertyInfo psPropertyInfo in psObject.Properties) { 
        if (psPropertyInfo.Name == "FullName") { 
         yield return psPropertyInfo.Value.ToString(); // yield it 
        } 
       } 
      } 

     } 

     static void Main(string[] args) { 
      foreach(string path in CmdletDirGlobbing(null,"C:\\*\\*\\*.txt")){ 
       System.Console.WriteLine(path); 
      } 
      foreach (string path in CmdletDirGlobbing("C:\\", "*\\*\\*.exe")) { 
       System.Console.WriteLine(path); 
      } 
      Console.ReadKey(); 
     } 

    } 
}