2012-09-29 17 views
6

Próbuję wyodrębnić hierarchię katalogu folderu do struktury danych w języku go. filepath.Walk wydaje się być drogą, ale wszystko, co mogę zrobić, to wydrukować nazwy plików i folderów. Oto, czego używam:Wyodrębnianie hierarchii katalogów przy użyciu języka 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) 
    } 
} 

ten wypisuje nazwy folderów, takich jak:

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 

na strukturze drzewa myślałem o użyciu coś jak:

type File struct { 
    Name string 
    Content string 
} 

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

ale oczywiście każdy sugestie są mile widziane.

Jak mogę przekonwertować to na strukturę drzewa w programie? Czy istnieje prostszy sposób na zrobienie tego?

Odpowiedz

3

AFAIK nie ma nic gotowego na to w standardowej librze Go.

Struktury drzew nadają się do rekursywnego podejścia. Zdefiniowałem metody addFile i addFolder dla typów plików i folderów. Zaczynając od folderu głównego, możesz wywołać te metody w Walk. Jeśli otrzymasz/b/c, zadzwonimy pod numer root.addFile(a, b, c), a.addFile(b, c), .

Zmieniłem także folder Folder.Folders na mapę, ponieważ ścieżka pliku zawsze daje nam pełne ścieżki, więc możemy je podzielić i wyszukać ich komponenty na mapie folderów.

Oto krótki i brudny kod, który prawdopodobnie zawiera błędy i nie sprawdza pełnego błędu. Działa tylko w bieżącym katalogu, ale powinno to być łatwe do naprawienia.

Dodałem również metodę String() do folderu, który jest rozpoznawany przez kompilator i będzie używany podczas drukowania wystąpień typu.

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

otrzymuję poczucie, że odpowiedź jest prawdą to jednak nie działa na moim komputerze mówiąc '30.09.2012 13:25:23 Oczekiwane zagnieżdżone strony folderów na stronach status wyjścia 1' – none

+0

Nie jestem pewien, co by to spowodowało. Jak już powiedziałem, jest to szybki i brudny kod ilustrujący koncepcję. Powinieneś być w stanie debugować i/lub zmieniać to z tego miejsca. –

+0

Ponieważ kod był dłuższy niż się spodziewałem, postanowiłem pójść w inny sposób z moim projektem. Tymczasem zostawię pytanie otwarte na jakiś czas, na wypadek gdyby ktoś wymyślił eleganckie rozwiązanie. Dzięki za pomoc .. – none

3

Potrzebowałem czegoś podobnego do małej aplikacji, więc napisałem małą osobną bibliotekę, która jest dostępna dla przyjemności oglądania on Github. Ponieważ potrzebowałem wbudowanej serializacji JSON dla zwróconego pliku os.FileInfo, dodałem go również.

Wiem, że przychodzi zbyt późno na oryginalnego autora tego pytania, ale mimo to publikuje go tutaj, na wypadek gdyby ktoś szukał czegoś podobnego. Wyciągnij wnioski łatwo zaakceptowane :)

0

trochę zmodyfikować

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

Proszę wyjaśnij, co edytowałeś i dlaczego teraz działa. –

Powiązane problemy