Go 中的目录列表:从简单到复杂
\n\n文件系统操作是任何编程语言的基本任务之一。在 Go 中,它的实现如此优雅,以至于即使是像 list directory in Go 这样的常规操作也变成了一次引人入胜的探索。如果您曾经问过自己:“如何在 Go 中获取文件夹中的文件列表?”——那么您来对地方了。今天,我们将讨论所有可能的方法,从简单的输出到带过滤的递归遍历。
\n\n为什么这个话题在 Stack Overflow 上如此受欢迎?因为 Go 提供了多种方法,选择正确的方法就成功了一半。我们将介绍经典的 os.ReadDir、已弃用的 ioutil.ReadDir(但在旧项目中仍可能遇到),以及用于递归遍历的强大 filepath.Walk。开始吧!
1. 最简单的列表:os.ReadDir
\n\n从 Go 1.16 开始,os 包新增了 ReadDir 方法,它已成为事实上的标准。它返回一个 os.DirEntry 对象的切片——这些是文件和文件夹的轻量级描述。如下所示:
package main\n\nimport (\n "fmt"\n "os"\n "log"\n)\n\nfunc main() {\n // 读取当前目录的内容\n entries, err := os.ReadDir(".")\n if err != nil {\n log.Fatal(err)\n }\n\n fmt.Println("当前文件夹的内容:")\n for _, entry := range entries {\n fmt.Printf("- %s (目录: %v)\\n", entry.Name(), entry.IsDir())\n }\n}\n\n\n这段代码将输出当前目录中的所有文件和文件夹。请注意:os.ReadDir 不会读取子文件夹——仅读取第一级。如果您需要递归地 list directory in Go,请继续阅读。
2. ioutil.ReadDir:旧但熟悉
\n\n在 Go 1.16 版本之前,所有人都使用 ioutil.ReadDir。它返回 []os.FileInfo——一个包含文件完整信息(大小、权限、修改时间)的更重结构。尽管该方法已被标记为 deprecated,您仍然可能在遗留代码中遇到它:
package main\n\nimport (\n "fmt"\n "io/ioutil"\n "log"\n)\n\nfunc main() {\n files, err := ioutil.ReadDir("./mydir")\n if err != nil {\n log.Fatal(err)\n }\n\n fmt.Println("mydir 中的文件(旧方法):")\n for _, file := range files {\n fmt.Printf("名称: %s, 大小: %d 字节\\n", file.Name(), file.Size())\n }\n}\n\n\n主要区别:ioutil.ReadDir 按文件名对结果进行排序(类似于 ls),而 os.ReadDir 则不会。如果顺序很重要,请使用 sort.Slice 或手动排序。
3. 使用 filepath.Walk 进行递归遍历
\n\n当需要遍历所有子文件夹时,filepath.Walk 就派上用场了。此函数遍历目录树,为找到的每个元素调用回调函数。非常适合备份、文件搜索或项目结构分析:
package main\n\nimport (\n "fmt"\n "os"\n "path/filepath"\n)\n\nfunc main() {\n root := "./myproject"\n err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {\n if err != nil {\n return err\n }\n fmt.Printf("找到: %s (大小: %d)\\n", path, info.Size())\n return nil\n })\n if err != nil {\n fmt.Println("遍历错误:", err)\n }\n}\n\n\n一个重要细节:filepath.Walk 会跟随符号链接,如果存在循环引用,可能会进入无限循环。对于生产环境,请使用 filepath.WalkDir(Go 1.16+)——它更轻量且更安全。
4. 过滤:仅 .go 文件或仅文件夹
\n\n通常不需要获取所有内容,而只需要特定类型的文件。让我们使用 strings.HasSuffix 和 IsDir() 检查来实现过滤