重构Go语言多层目录JSON文件读取函数的优化方案咨询
重构Go目录遍历代码:替代硬编码多层循环的方案
初始项目结构
- main.go
/data/11.json
/22.json
/33.json
原有适配初始结构的代码
const ( data = "./data" ) type Hello struct { S string `json:"hello"` } func myFunc() { folders, err := os.ReadDir(data) if err != nil { log.Fatalf("read dir: %s", err) } for _, folder := range folders { path := filepath.Join(data, folder.Name()) files, err := os.ReadDir(path) if err != nil { log.Fatalf("read dir: %s", err) } for _, file := range files { pathToFile := filepath.Join(path, file.Name()) b, err := os.ReadFile(pathToFile) if err != nil { log.Println(err) } h := Hello{} err = json.Unmarshal(b, &h) if err != nil { log.Printf("unmarshall error: %w\n", err) } fmt.Println(h) } } }
调整后的项目结构
- main.go
/data/dog/11.json
/22.json
/cat/33.json
待优化的硬编码多层循环实现
func myfunc() { subFolders, err := os.ReadDir(data) if err != nil { log.Fatalf("read dir: %s", err) } for _, subFolder := range subFolders { pathToSubFolder := filepath.Join(data, subFolder.Name()) folders, err := os.ReadDir(pathToSubFolder) if err != nil { log.Fatalf("read dir1: %s", err) } for _, folder := range folders { path := filepath.Join(pathToSubFolder, folder.Name()) files, err := os.ReadDir(path) if err != nil { log.Fatalf("read dir2: %s", err) } for _, file := range files { pathToFile := filepath.Join(path, file.Name()) b, err := os.ReadFile(pathToFile) if err != nil { log.Println(err) } h := Hello{} err = json.Unmarshal(b, &h) if err != nil { log.Printf("unmarshall error: %w\n", err) } fmt.Println(h) } } } }
优化方案:使用递归遍历或filepath.WalkDir
方案1:递归遍历目录
通过递归函数处理任意层级的目录,无需硬编码循环次数:
func processDir(dir string) error { entries, err := os.ReadDir(dir) if err != nil { return fmt.Errorf("read dir %s: %w", dir, err) } for _, entry := range entries { fullPath := filepath.Join(dir, entry.Name()) if entry.IsDir() { // 递归处理子目录 if err := processDir(fullPath); err != nil { log.Printf("skip dir %s: %v", fullPath, err) continue } } else { // 只处理.json文件 if filepath.Ext(entry.Name()) != ".json" { continue } // 读取并解析JSON b, err := os.ReadFile(fullPath) if err != nil { log.Printf("read file %s: %v", fullPath, err) continue } var h Hello if err := json.Unmarshal(b, &h); err != nil { log.Printf("unmarshal %s: %w", fullPath, err) continue } fmt.Println(h) } } return nil } func myFunc() { if err := processDir(data); err != nil { log.Fatalf("process root dir: %v", err) } }
方案2:使用filepath.WalkDir(Go 1.16+推荐)
标准库path/filepath的WalkDir函数可以自动遍历目录树,代码更简洁:
func myFunc() { err := filepath.WalkDir(data, func(path string, d fs.DirEntry, err error) error { if err != nil { log.Printf("access path %s: %v", path, err) return fs.SkipDir // 跳过当前目录的后续处理 } // 跳过目录,只处理文件 if d.IsDir() { return nil } // 只处理.json后缀的文件 if filepath.Ext(d.Name()) != ".json" { return nil } // 读取并解析JSON b, err := os.ReadFile(path) if err != nil { log.Printf("read file %s: %v", path, err) return nil // 继续处理其他文件 } var h Hello if err := json.Unmarshal(b, &h); err != nil { log.Printf("unmarshal %s: %w", path, err) return nil } fmt.Println(h) return nil }) if err != nil { log.Fatalf("walk dir: %v", err) } }
方案优势
- 扩展性强:无论后续目录层级如何调整,代码无需修改
- 可读性高:逻辑清晰,分离目录遍历与文件处理逻辑
- 容错性好:单个目录/文件处理失败不影响整体流程(可根据需求调整错误处理策略)
内容的提问来源于stack exchange,提问作者1oko
相关产品推荐
相关产品推荐

