Список каталогов в Go

197

Я пытался выяснить, как просто перечислить файлы и папки в одном каталоге в Go.

Я нашел filepath.Walk, но он автоматически попадает в подкаталоги, чего я не хочу. Все мои другие поиски не нашли ничего лучшего.

Я уверен, что эта функциональность существует, но ее было действительно трудно найти. Дайте мне знать, если кто-нибудь знает, где я должен искать. Спасибо.

Бехрам Мистри
источник

Ответы:

359

Вы можете попробовать использовать функцию ReadDir в io/ioutilпакете. Согласно документам:

ReadDir читает каталог с именем dirname и возвращает список отсортированных записей каталога.

Результирующий фрагмент содержит os.FileInfoтипы, которые предоставляют методы, перечисленные здесь . Вот базовый пример, в котором перечислены все элементы в текущем каталоге (папки включены, но специально не помечены - вы можете проверить, является ли элемент папкой, используя IsDir()метод):

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
источник
7
Если вам нужны только имена содержимого каталога, а скорость важна , учтите, что использование Readdirnames на несколько порядков быстрее (для меня примерно в 20 раз быстрее)
SquattingSlavInTracksuit
2
@SquattingSlavInTracksuit: я повысил ваш комментарий до ответа, потому что у меня не было привилегий для комментариев в то время. Если вы предпочитаете ответить и получить кредит, ЛМК.
Якоб Копчинский
2
@SquattingSlavInTracksuit - это всего лишь один порядок величины: P
nadavvadan
78

Еще проще, используйте 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
}
Фатих Арслан
источник
8
Обратите внимание, чтоGlob ignores file system errors such as I/O errors reading directories. The only possible returned error is ErrBadPattern, when pattern is malformed.
Джон
3
Не забудьте понять, что делает Glob, прежде чем использовать его. golang.org/pkg/path/filepath/#Glob
Anfernee
67

Мы можем получить список файлов внутри папки в файловой системе, используя различные стандартные библиотечные функции 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. Использование filepath.Walk

path/filepathПакет обеспечивает удобный способ для сканирования всех файлов в каталоге, он будет автоматически сканировать каждый подкаталоги в каталоге.

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. Использование ioutil.ReadDir

ioutil.ReadDir читает каталог с именем dirname и возвращает список записей каталога, отсортированных по имени файла.

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. Использование os.File.Readdir

Readdir считывает содержимое каталога, связанного с файлом, и возвращает фрагмент до n значений FileInfo, как было бы возвращено Lstat, в порядке каталога. Последующие вызовы в том же файле приведут к дальнейшему 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
}

Результаты тестов.

эталонный балл

Получить более подробную информацию об этом блоге

manigandand
источник
3
Самый полный ответ здесь. Стоит отметить, что этот тест не использует память и не выделяет ресурсы. Возможно, более быстрые реализации используют больше памяти. Также возможно, что число ядер ЦП на компьютере тестировщика болит / помогает одновременно filepath.Walk. Кроме того, filepath.Walkподдерживает рекурсивное приличное время os.File.Readdirи ioutil.ReadDirне делает.
Xeoncross
24

ioutil.ReadDirэто хорошая находка, но если вы щелкнете и посмотрите на источник, то увидите, что он вызывает метод Readdir из os.File . Если вы согласны с порядком каталогов и вам не нужен отсортированный список, то этот метод Readdir - все, что вам нужно.

Соня
источник
7

Из вашего описания, что вы, вероятно, хотите, это os.Readdirnames .

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

Readdirnames считывает содержимое каталога, связанного с файлом, и возвращает фрагмент до n имен файлов в каталоге в порядке каталога. Последующие обращения к тому же файлу приведут к дальнейшим именам.

...

Если n <= 0, Readdirnames возвращает все имена из каталога в одном слайсе.

Отрывок:

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

Кредит SquattingSlavInTracksuit «S комментарий ; Я бы предложил продвинуть их комментарий к ответу, если бы мог.

Яков Копчинский
источник