2012-09-29 13 views
6

Sto cercando di estrarre la gerarchia di directory di una cartella in una struttura dati in linguaggio go. filepath.Walk sembra essere la strada da percorrere, ma tutto quello che posso fare finora è stampare i nomi di file e cartelle. Ecco quello che sto usando:estrazione della gerarchia di directory utilizzando la lingua go

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

questa stampa i nomi delle cartelle, come:

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 

per struttura ad albero Avevo pensato di usare qualcosa come:

type File struct { 
    Name string 
    Content string 
} 

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

ma naturalmente qualsiasi i suggerimenti sono benvenuti

Come posso convertirlo in una struttura ad albero in go? C'è un modo più semplice per farlo?

risposta

3

AFAIK non c'è nulla di pronto per questo in lib standard Go.

Le strutture ad albero si prestano bene ad un approccio ricorsivo. Ho definito i metodi addFile e addFolder sui tipi di file e cartelle. A partire da una cartella radice, è possibile chiamare questi metodi in Walk. Se si ottiene a/b/c, chiameremo root.addFile(a, b, c), a.addFile(b, c), b.addFile(c).

Ho anche cambiato Folder.Folders su una mappa, perché filepath.Walk ci fornisce sempre percorsi completi, quindi possiamo suddividerli e cercare i loro componenti nella mappa delle cartelle.

Ecco un codice veloce e sporco che probabilmente contiene errori e non esegue il controllo completo degli errori. Funziona solo per la directory corrente, ma dovrebbe essere facile da risolvere.

Ho anche aggiunto un metodo String() su Cartella, che viene riconosciuto dal compilatore e verrà utilizzato durante la stampa di istanze 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

Ho la sensazione che la vostra risposta è vero, però non viene eseguito sul mio computer dicendo '2012/09/30 13:25:23 Atteso annidati pagine di cartelle in pagine exit status 1' – none

+0

Non sai cosa potrebbe causare questo. Come ho detto, questo è un codice veloce e sporco per illustrare il concetto. Dovresti essere in grado di eseguire il debug e/o modificarlo da lì. –

+0

Poiché il codice era più lungo di quanto mi aspettassi, ho deciso di seguire un'altra strada con il mio design. Nel frattempo lascerò la domanda aperta per un po 'nel caso qualcuno possa trovare una soluzione elegante. Grazie per l'aiuto. – none

3

avevo bisogno di qualcosa di simile per una piccola applicazione di mine così ho scritto una piccola libreria separata, che è disponibile per il vostro piacere di visualizzazione on Github. Poiché avevo bisogno della serializzazione JSON integrata per il file os.FileInfo restituito, l'ho aggiunta anch'essa.

So che arriva troppo tardi per l'autore originale di questa domanda ma pubblicandola qui comunque nel caso qualcuno stia cercando qualcosa di simile. Tirare le richieste prontamente accettate :)

0

Poco modificare

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

Spiega cosa hai modificato e perché funziona ora. –

Problemi correlati