- Muszę napisać funkcję, która po podaniu ścieżki do folderu skanuje pliki zakorzenione w tym folderze.
- A potem muszę wyświetlić strukturę katalogów w tym folderze.
Wiem, jak zrobić 2 (zamierzam użyć jstree, aby wyświetlić go w przeglądarce).
Wiem, jak zrobić 2 (zamierzam użyć jstree, aby wyświetlić go w przeglądarce).
Odpowiedzi:
EDYCJA : Wystarczająco dużo osób wciąż trafia na tę odpowiedź, że pomyślałem, że zaktualizuję ją dla API Go1. To jest działający przykład filepath.Walk () . Oryginał znajduje się poniżej.
package main
import (
"path/filepath"
"os"
"flag"
"fmt"
)
func visit(path string, f os.FileInfo, err error) error {
fmt.Printf("Visited: %s\n", path)
return nil
}
func main() {
flag.Parse()
root := flag.Arg(0)
err := filepath.Walk(root, visit)
fmt.Printf("filepath.Walk() returned %v\n", err)
}
Należy pamiętać, że filepath.Walk przechodzi przez drzewo katalogów rekurencyjnie.
Oto przykładowy bieg:
$ mkdir -p dir1/dir2
$ touch dir1/file1 dir1/dir2/file2
$ go run walk.go dir1
Visited: dir1
Visited: dir1/dir2
Visited: dir1/dir2/file2
Visited: dir1/file1
filepath.Walk() returned <nil>
ORYGINALNA ODPOWIEDŹ NASTĘPUJĄCA: Interfejs ścieżek do plików spacerowych zmienił się co tydzień w 2011-09-16, patrz http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . Poniższy kod nie będzie działał z wydanymi wersjami GO w najbliższej przyszłości.
Właściwie w standardowej bibliotece znajduje się funkcja przeznaczona tylko do tego: filepath.Walk .
package main
import (
"path/filepath"
"os"
"flag"
)
type visitor int
// THIS CODE NO LONGER WORKS, PLEASE SEE ABOVE
func (v visitor) VisitDir(path string, f *os.FileInfo) bool {
println(path)
return true
}
func (v visitor) VisitFile(path string, f *os.FileInfo) {
println(path)
}
func main() {
root := flag.Arg(0)
filepath.Walk(root, visitor(0), nil)
}
filepath.Walk
przy okazji nie podąża za linkami symbolicznymi.
filepath.Walk
zwrotne @FrancescoPasa zostanie uruchomione na dowiązaniach symbolicznych (zarówno plik, jak i katalog). Tak, nie podąży za nimi, ale wywołanie zwrotne rozpozna łącze symboliczne i podejmie dalsze działania, tj. Kontynuację, filepath.Walk
upewniając się najpierw, że ścieżka nie została już odwiedzona.
Oto sposób na uzyskanie informacji o plikach w katalogu.
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
dirname := "." + string(filepath.Separator)
d, err := os.Open(dirname)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
defer d.Close()
fi, err := d.Readdir(-1)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
for _, fi := range fi {
if fi.Mode().IsRegular() {
fmt.Println(fi.Name(), fi.Size(), "bytes")
}
}
}
Readdir
parametrem metody jest n
plik int
. Jeśli n <= 0
, Readdir
zwraca wszystkie FileInfo
z katalogu w jednym wycinku.
os
func (FileMode) IsRegular
.
Oto przykład rekurencyjnej pętli przez wszystkie pliki i katalogi. Zauważ, że jeśli chcesz wiedzieć, czy dołączana ścieżka jest katalogiem, po prostu zaznacz "f.IsDir ()".
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
searchDir := "c:/path/to/dir"
fileList := []string{}
err := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
fileList = append(fileList, path)
return nil
})
for _, file := range fileList {
fmt.Println(file)
}
}
main
Metoda nie powinna mieć ([]string, error)
args i trzeba coś zrobić z err
. Chyba że w chwili udzielenia odpowiedzi był ważny? Zdecydowanie błąd kompilacji w nowszych wersjach. W przeciwnym razie bardzo przydatne, dziękuję.
Pakiet github.com/kr/fs
zawiera Walker
bardzo ciekawe API.
Standardowy pakiet Go ioutil
ma wbudowaną funkcję dla tego przypadku, patrz poniższy przykład
func searchFiles(dir string) { // dir is the parent directory you what to search
files, err := ioutil.ReadDir(dir)
if err != nil {
log.Fatal(err)
}
for _, file := range files {
fmt.Println(file.Name())
}
}
Pamiętaj, że „Spacer nie podąża za dowiązaniami symbolicznymi”, więc jeśli chcesz napisać funkcję, która to robi, polecam ioutil.ReadDir . Mój własny test porównawczy wykazał, że jest szybszy i mniej obciążający pamięć niż filepath.Glob .
Dodatkowo ioutil.ReadDir
sortuje pliki według basename przy użyciu podstawowego porównania ciągów ( strA > strB
). Jako deweloper generalnie sortuję nazwy katalogów, wykonując odwrotne porównanie liczbowe (na przykład najnowsza kompilacja jako pierwsza). Jeśli tak jest również w twoim przypadku, lepiej zadzwonić bezpośrednio do os.ReadDir ( ioutil.ReadDir
wywołuje to pod okładkami) i przeprowadzić sortowanie samodzielnie.
Oto przykład ReadDir
części z sortowaniem numerycznym:
// ReadDirNumSort - Same as ioutil/ReadDir but uses returns a Numerically
// Sorted file list.
//
// Taken from https://golang.org/src/io/ioutil/ioutil.go
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
// Modified Sort method to use Numerically sorted names instead.
// It also allows reverse sorting.
func ReadDirNumSort(dirname string, reverse bool) ([]os.FileInfo, error) {
f, err := os.Open(dirname)
if err != nil {
return nil, err
}
list, err := f.Readdir(-1)
f.Close()
if err != nil {
return nil, err
}
if reverse {
sort.Sort(sort.Reverse(byName(list)))
} else {
sort.Sort(byName(list))
}
return list, nil
}
// byName implements sort.Interface.
type byName []os.FileInfo
func (f byName) Len() int { return len(f) }
func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
func (f byName) Less(i, j int) bool {
nai, err := strconv.Atoi(f[i].Name())
if err != nil {
return f[i].Name() < f[j].Name()
}
naj, err := strconv.Atoi(f[j].Name())
if err != nil {
return f[i].Name() < f[j].Name()
}
return nai < naj
}
Możesz tutaj skorzystać z funkcji curry, abyś mógł w pełni wykorzystać wyszukiwanie
func visit(files *[]string) filepath.WalkFunc {
return func (path string, info os.FileInfo, err error) error {
// maybe do this in some if block
*files = append(*files, path)
return nil
}
}