Wyświetl katalog w Go

197

Próbowałem wymyślić, jak po prostu wyświetlić listę plików i folderów w jednym katalogu w Go.

Znalazłem filepath.Walk, ale automatycznie przechodzi do podkatalogów, czego nie chcę. Wszystkie moje inne wyszukiwania nie poprawiły niczego.

Jestem pewien, że ta funkcjonalność istnieje, ale bardzo trudno ją znaleźć. Daj mi znać, jeśli ktoś wie, gdzie powinienem szukać. Dzięki.

Behram Mistree
źródło

Odpowiedzi:

359

Możesz spróbować użyć funkcji ReadDir w io/ioutilpakiecie. Według dokumentów:

ReadDir odczytuje katalog o nazwie dirname i zwraca listę posortowanych pozycji katalogu.

Powstały plasterek zawiera os.FileInfotypy, które zapewniają metody wymienione tutaj . Oto podstawowy przykład, który wyświetla nazwę wszystkiego w bieżącym katalogu (foldery są uwzględnione, ale nie są specjalnie oznaczone - możesz sprawdzić, czy element jest folderem, używając IsDir()metody):

package main

import (
    "fmt"
    "io/ioutil"
     "log"
)

func main() {
    files, err := ioutil.ReadDir("./")
    if err != nil {
        log.Fatal(err)
    }

    for _, f := range files {
            fmt.Println(f.Name())
    }
}
RocketDonkey
źródło
7
Jeśli chcesz tylko nazwy zawartości katalogu i szybkość ma zasadnicze znaczenie, pamiętaj, że użycie Readdirnames jest o rząd wielkości szybsze (około 20 razy szybsze dla mnie)
SquattingSlavInTracksuit
2
@SquattingSlavInTracksuit: Promowałem twój komentarz tutaj na odpowiedź, ponieważ nie miałem wtedy uprawnień do komentowania. Jeśli wolisz odpowiedzieć na to pytanie i uzyskać kredyt, LMK.
Jacob Kopczyński
2
@SquattingSlavInTracksuit - to tylko jeden rząd wielkości: P
nadavvadan
78

Jeszcze prostsze, użyj path/filepath:

package main    

import (
    "fmt"
    "log"
    "path/filepath"
)

func main() {
    files, err := filepath.Glob("*")
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(files) // contains a list of all files in the current directory
}
Fatih Arslan
źródło
8
Zauważ, żeGlob ignores file system errors such as I/O errors reading directories. The only possible returned error is ErrBadPattern, when pattern is malformed.
Jon
3
Pamiętaj, aby zrozumieć, co robi Glob przed użyciem. golang.org/pkg/path/filepath/#Glob
Anfernee
66

Możemy uzyskać listę plików w folderze w systemie plików, używając różnych standardowych funkcji biblioteki golang.

  1. filepath.Walk
  2. ioutil.ReadDir
  3. os.File.Readdir

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
)

func main() {
    var (
        root  string
        files []string
        err   error
    )

    root := "/home/manigandan/golang/samples"
    // filepath.Walk
    files, err = FilePathWalkDir(root)
    if err != nil {
        panic(err)
    }
    // ioutil.ReadDir
    files, err = IOReadDir(root)
    if err != nil {
        panic(err)
    }
    //os.File.Readdir
    files, err = OSReadDir(root)
    if err != nil {
        panic(err)
    }

    for _, file := range files {
        fmt.Println(file)
    }
}
  1. Korzystanie z pliku filepath.Walk

path/filepathPakiet zapewnia wygodny sposób, aby skanować wszystkie pliki w katalogu, zostanie ona automatycznie skanować każdy podkatalogów w katalogu.

func FilePathWalkDir(root string) ([]string, error) {
    var files []string
    err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
        if !info.IsDir() {
            files = append(files, path)
        }
        return nil
    })
    return files, err
}
  1. Korzystanie z ioutil.ReadDir

ioutil.ReadDir odczytuje katalog o nazwie dirname i zwraca listę pozycji katalogu posortowanych według nazwy pliku.

func IOReadDir(root string) ([]string, error) {
    var files []string
    fileInfo, err := ioutil.ReadDir(root)
    if err != nil {
        return files, err
    }

    for _, file := range fileInfo {
        files = append(files, file.Name())
    }
    return files, nil
}
  1. Korzystanie z os.File.Readdir

Readdir odczytuje zawartość katalogu powiązanego z plikiem i zwraca kawałek do n wartości FileInfo, tak jak zwracałby to Lstat, w kolejności katalogów. Kolejne wywołania tego samego pliku przyniosą dalsze FileInfos.

func OSReadDir(root string) ([]string, error) {
    var files []string
    f, err := os.Open(root)
    if err != nil {
        return files, err
    }
    fileInfo, err := f.Readdir(-1)
    f.Close()
    if err != nil {
        return files, err
    }

    for _, file := range fileInfo {
        files = append(files, file.Name())
    }
    return files, nil
}

Wyniki testu.

wynik testu porównawczego

Uzyskaj więcej informacji na temat tego posta na blogu

Manigandand
źródło
3
Najbardziej kompletna odpowiedź tutaj. Warto zauważyć, że ten test porównawczy nie odnotowuje użycia pamięci ani alokacji. Możliwe, że szybsze wdrożenia zużywają więcej pamięci. Możliwe jest również, że liczba rdzeni procesora na komputerze testera boli / pomaga współbieżnie filepath.Walk. Ponadto filepath.Walkobsługuje rekurencyjne przyzwoite podczas os.File.Readdiri ioutil.ReadDirnie.
Xeoncross,
24

ioutil.ReadDirjest dobrym znaleziskiem, ale jeśli klikniesz i spojrzysz na źródło, zobaczysz, że wywołuje ono metodę Readdir pliku os.File . Jeśli nie masz nic przeciwko kolejności katalogów i nie potrzebujesz sortowania listy, to wystarczy ta metoda Readdir.

Sonia
źródło
7

Z twojego opisu prawdopodobnie potrzebujesz os.Readdirnames .

func (f *File) Readdirnames(n int) (names []string, err error)

Readdirnames odczytuje zawartość katalogu powiązanego z plikiem i zwraca w folderze kawałek maksymalnie n nazw plików. Kolejne wywołania tego samego pliku przyniosą dalsze nazwy.

...

Jeśli n <= 0, Readdirnames zwraca wszystkie nazwy z katalogu w jednym wycinku.

Skrawek:

file, err := os.Open(path)
if err != nil {
    return err
}
names, err := file.Readdirnames(0)
if err != nil {
    return err
}
fmt.Println(names)

Kredyt dla SquattingSlavInTracksuit „s komentarzem ; Gdybym mógł, zasugerowałbym promocję ich komentarza na odpowiedź.

Jakub Kopczyński
źródło