在Go中列出目录


197

我一直在尝试找出如何简单地在Go中的单个目录中列出文件和文件夹。

我已经找到了filepath.Walk,但是它会自动进入子目录,这是我不想要的。我所有其他搜索都没有发现更好的结果。

我确定该功能存在,但确实很难找到。让我知道是否有人知道我应该去哪里。谢谢。

Answers:


359

您可以尝试使用软件包中的ReadDir函数io/ioutil。根据文档:

ReadDir读取目录名命名的目录,并返回已排序目录条目的列表。

结果切片包含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())
    }
}

7
如果你只希望名字的目录和速度的内容是本质,注意使用Readdirnames数量级的速度(快20倍左右为我)
SquattingSlavInTracksuit

2
@SquattingSlavInTracksuit:我在这里将您的评论提升为答案,因为当时我没有评论权限。如果您愿意回答并获得荣誉,LMK。
Jacob Kopczynski

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.
2015年

3
使用前,请务必了解Glob的功能。 golang.org/pkg/path/filepath/#Glob
安芬尼

65

我们可以使用各种golang标准库函数获取文件系统上文件夹内文件的列表。

  1. 文件路径
  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命名的目录,并返回按filename排序的目录条目列表。

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读取与file关联的目录的内容,并按目录顺序返回最多n个FileInfo值的切片,这将由Lstat返回。对同一文件的后续调用将进一步产生FileInfo。

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
}

基准结果。

基准分数

获取有关此博客文章的更多详细信息


3
这里最完整的答案。值得注意的是,该基准测试没有报告内存使用或分配。更快的实现可能使用更多的内存。测试仪计算机上的CPU内核数量也可能损害/帮助并发filepath.Walk。此外,filepath.Walk支持递归体面的while os.File.Readdirioutil.ReadDir不支持。
Xeoncross

24

ioutil.ReadDir是一个很好的发现,但是如果单击并查看源代码,则会看到它调用了os.File的Readdir方法。如果您对目录顺序感到满意,并且不需要对列表进行排序,那么只需使用此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评论 ; 如果可以的话,我建议将他们的评论提升为答案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.