2012-09-29 15 views
6

Estoy tratando de extraer la jerarquía de directorios de una carpeta en una estructura de datos en el idioma go. filepath.Walk parece ser el camino a seguir, pero todo lo que puedo hacer hasta ahora es imprimir los nombres de los archivos y carpetas. Esto es lo que estoy usando:extracción de la jerarquía de directorios usando go language

func main() { 
    visit := func(path string, info os.FileInfo, err error) error { 
     if info.IsDir() { 
      fmt.Println("dir: ", path) 
     } else { 
      fmt.Println("file: ", path) 
     } 
     return nil 
    } 

    err := filepath.Walk("./", visit) 
    if err != nil { 
     log.Fatal(err) 
    } 
} 

este imprime los nombres de las carpetas como:

dir: folder1 
file: folder1/file1.txt 
file: folder1/file2.txt 
file: folder1/file3.txt 
file: folder1/file4.txt 
dir: folder1/folder2 
file: folder1/folder2/file5.txt 
file: folder1/folder2/file6.txt 
file: folder1/folder2/file7.txt 
file: folder1/folder2/file8.txt 
file: folder1/folder2/file9.txt 

de estructura de árbol Pensé en usar algo como:

type File struct { 
    Name string 
    Content string 
} 

type Folder struct { 
    Name string 
    Files []File 
    Folders []Folder 
} 

pero por supuesto cualquier sugerencias son bienvenidas

¿Cómo puedo convertir esto en una estructura de árbol en go? ¿Hay alguna forma más fácil de hacer esto?

Respuesta

3

AFAIK no hay nada preparado para esto en la versión estándar de Go.

Las estructuras de árbol se prestan bien a un enfoque recursivo. Definí los métodos addFile y addFolder en sus tipos de archivos y carpetas. Comenzando con una carpeta raíz, puede llamar a estos métodos en Walk. Si obtiene a/b/c, llamaremos al root.addFile(a, b, c), a.addFile(b, c), b.addFile(c).

También cambié Folder.Folders a un mapa, porque filepath.Walk siempre nos da rutas de acceso completas, por lo que podemos dividirlas y buscar sus componentes en el mapa de carpetas.

Aquí hay un código rápido y sucio que probablemente tiene errores y no hace una comprobación completa de errores. Solo funciona para el directorio actual, pero debería ser fácil de arreglar.

También agregué un método String() en la carpeta, que es reconocido por el compilador y se utilizará al imprimir instancias del tipo.

package main 

import (
    "log" 
    "os" 
    "path/filepath" 
    "strings" 
) 

type File struct { 
    Name string 
} 

type Folder struct { 
    Name string 
    Files []File 
    Folders map[string]*Folder 
} 

func newFolder(name string) *Folder { 
    return &Folder{name, []File{}, make(map[string]*Folder)} 
} 

func (f *Folder) getFolder(name string) *Folder { 
    if nextF, ok := f.Folders[name]; ok { 
     return nextF 
    } else { 
     log.Fatalf("Expected nested folder %v in %v\n", name, f.Name) 
    } 
    return &Folder{} // cannot happen 
} 

func (f *Folder) addFolder(path []string) { 
    for i, segment := range path { 
     if i == len(path)-1 { // last segment == new folder 
      f.Folders[segment] = newFolder(segment) 
     } else { 
      f.getFolder(segment).addFolder(path[1:]) 
     } 
    } 
} 

func (f *Folder) addFile(path []string) { 
    for i, segment := range path { 
     if i == len(path)-1 { // last segment == file 
      f.Files = append(f.Files, File{segment}) 
     } else { 
      f.getFolder(segment).addFile(path[1:]) 
      return 
     } 
    } 
} 

func (f *Folder) String() string { 
    var str string 
    for _, file := range f.Files { 
     str += f.Name + string(filepath.Separator) + file.Name + "\n" 
    } 
    for _, folder := range f.Folders { 
     str += folder.String() 
    } 
    return str 
} 

func main() { 
    startPath := "." 
    rootFolder := newFolder(startPath) 

    visit := func(path string, info os.FileInfo, err error) error { 
     segments := strings.Split(path, string(filepath.Separator)) 
     if info.IsDir() { 
      if path != startPath { 
       rootFolder.addFolder(segments) 
      } 
     } else { 
      rootFolder.addFile(segments) 
     } 
     return nil 
    } 

    err := filepath.Walk(startPath, visit) 
    if err != nil { 
     log.Fatal(err) 
    } 

    log.Printf("%v\n", rootFolder) 
} 
+0

Me da la sensación de que su respuesta es cierto sin embargo que no se ejecuta en el ordenador diciendo '30/09/2012 13:25:23 Esperado anidado las páginas de la carpeta en las páginas salen del estado 1' – none

+0

No estoy seguro de qué podría causar esto. Como dije, este es un código rápido y sucio para ilustrar el concepto. Debería poder depurarlo y/o cambiarlo desde allí. –

+0

Como el código era más largo de lo que esperaba, decidí ir por otro camino con mi diseño. Mientras tanto, dejaré la pregunta abierta por un tiempo en caso de que alguien pueda encontrar una solución elegante. Gracias por la ayuda .. – none

3

necesitaba algo similar para una pequeña aplicación de la mía, así que escribí una pequeña biblioteca independiente que está disponible para su placer visual on Github. Como necesitaba la serialización JSON incorporada para el os.FileInfo devuelto, también lo agregué.

Sé que llega demasiado tarde para el autor original de esta pregunta, pero publicarlo aquí de todos modos en caso de que alguien esté buscando algo similar. Tire de solicitudes aceptadas fácilmente :)

0

Poco modificar

package main 

import (
    "fmt" 
    "path" 
    "strings" 
) 

type File struct { 
    Id string 
    Name string 
} 

type Folder struct { 
    Name string 
    Files []File 
    Folders map[string]*Folder 
} 

func newFolder(name string) *Folder { 
    return &Folder{name, []File{}, make(map[string]*Folder)} 
} 

func (f *Folder) getFolder(name string) *Folder { 
    if nextF, ok := f.Folders[name]; ok { 
     return nextF 
    } else if f.Name == name { 
     return f 
    } else { 
     return &Folder{} 
    } 
} 

func (f *Folder) existFolder(name string) bool { 
    for _, v := range f.Folders { 
     if v.Name == name { 
      return true 
     } 
    } 
    return false 
} 

func (f *Folder) addFolder(folderName string) { 
    if !f.existFolder(folderName) { 
     f.Folders[folderName] = newFolder(folderName) 
    } 
} 

func (f *Folder) addFile(fileName string, fileId string) { 
    f.Files = append(f.Files, File{fileId, fileName}) 
} 

func (f *Folder) getList() (result []map[string]interface{}) { 
    for _, v := range f.Folders { 
     result = append(result, map[string]interface{}{ 
      "name": v.Name, 
      "type": "folder", 
     }) 
    } 

    for _, v := range f.Files { 
     result = append(result, map[string]interface{}{ 
      "id": v.Id, 
      "name": v.Name, 
      "type": "file", 
     }) 
    } 
    return 
} 

func isFile(str string) bool { 
    if path.Ext(str) != "" { 
     return true 
    } 
    return false 
} 

func DeleteEmptyElements(s []string) []string { 
    var r []string 
    for _, str := range s { 
     if str != "" { 
      r = append(r, str) 
     } 
    } 
    return r 
} 

type IS map[string]string 

func main() { 
    arrayPaths := []interface{}{ 
     IS{ 
      "id":  "1", 
      "filePath": "/print/some/com.png", 
     }, 
     IS{ 
      "id":  "2", 
      "filePath": "/print/some2/com412412.png", 
     }, 
     IS{ 
      "id":  "3", 
      "filePath": "/print/some2/41241241241.png", 
     }, 
    } 

    breadcrumb := "/print/some2" 

    startPath := "/" 
    rootFolder := newFolder(startPath) 

    for _, path := range arrayPaths { 
     filePath := path.(IS)["filePath"] 
     fileId := path.(IS)["id"] 
     splitPath := DeleteEmptyElements(strings.Split(filePath, "/")) 
     tmpFolder := rootFolder 
     for _, item := range splitPath { 
      if isFile(item) { 
       tmpFolder.addFile(item, fileId) 
      } else { 
       if item != startPath { 
        tmpFolder.addFolder(item) 
       } 
       tmpFolder = tmpFolder.getFolder(item) 
      } 
     } 
    } 

    currentFolder := rootFolder.getFolder("/") 
    breadcrumbElements := DeleteEmptyElements(strings.Split(breadcrumb, "/")) 
    for i, v := range breadcrumbElements { 
     if currentFolder.existFolder(v) { 
      currentFolder = currentFolder.getFolder(v) 
      if i == len(breadcrumbElements)-1 { 
       break 
      } 
     } else { 
      currentFolder = currentFolder.getFolder(v) 
     } 
    } 

    fmt.Println(currentFolder.getList()) 
} 
+1

Por favor explique lo que ha editado y por qué funciona ahora. –

Cuestiones relacionadas