You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

重构Go语言多层目录JSON文件读取函数的优化方案咨询

重构Go目录遍历代码:替代硬编码多层循环的方案

初始项目结构

  • main.go
  • /data
    • /1
      • 1.json
    • /2
      • 2.json
    • /3
      • 3.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
      • /1
        • 1.json
      • /2
        • 2.json
    • /cat
      • /3
        • 3.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)
    }
}

方案优势

  1. 扩展性强:无论后续目录层级如何调整,代码无需修改
  2. 可读性高:逻辑清晰,分离目录遍历与文件处理逻辑
  3. 容错性好:单个目录/文件处理失败不影响整体流程(可根据需求调整错误处理策略)

内容的提问来源于stack exchange,提问作者1oko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 03:10:37