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

Golang filepath.WalkFunc使用报错:索引越界问题求助

Go代码索引越界问题排查与修复

问题背景

需求是在./task/目录下的一批名称相似、大小相同的文件中找到CSV文件,并打印其第5行第3列(索引4和2)的数值。原代码运行时触发索引越界panic,错误信息及原代码如下:

原代码

package main

import (
    "encoding/csv"
    "fmt"
    "os"
    "path/filepath"
)

var s [][]string

func walkfunc(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    buf, err1 := os.Open(path)
    if err1 == nil {
        var err2 error
        r := csv.NewReader(buf)
        s, err2 = r.ReadAll()
        if err2 == nil {
            fmt.Printf("found: %v", s[4][2])
        }
    }
    defer buf.Close()
    return nil
}
func main() {
    const root = "./task/"
    if err := filepath.Walk(root, walkfunc); err != nil {
        fmt.Printf("error: %v", err)
    }
}

错误输出

GOROOT=/usr/local/go #gosetup
GOPATH=/usr/local/go/bin #gosetup
/usr/local/go/bin/go build -o /private/var/folders/j2/ybr0drz13yq31dc67zmvkb1w0000gn/T/GoLand/___go_build_qwasd3_go /Users/user/Downloads/zadacha/qwasd3.go #gosetup
/private/var/folders/j2/ybr0drz13yq31dc67zmvkb1w0000gn/T/GoLand/___go_build_qwasd3_go
panic: runtime error: index out of range [4] with length 3

goroutine 1 [running]:
main.walkfunc({0x14000018120?, 0x0?}, {0x14000098d88?, 0x10247fe40?}, {0x0?, 0x0?})
        /Users/user/Downloads/zadacha/qwasd3.go:23 +0x28c
path/filepath.walk({0x14000018120, 0xe}, {0x1024c9cf8, 0x140000685b0}, 0x1024c9338)
        /usr/local/go/src/path/filepath/path.go:433 +0xd0
path/filepath.walk({0x10248d4a8, 0x7}, {0x1024c9cf8, 0x140000684e0}, 0x1024c9338)
        /usr/local/go/src/path/filepath/path.go:457 +0x1fc
path/filepath.Walk({0x10248d4a8, 0x7}, 0x1024c9338)
        /usr/local/go/src/path/filepath/path.go:520 +0x6c
main.main()
        /Users/user/Downloads/zadacha/qwasd3.go:37 +0x30

Process finished with the exit code 2

错误原因分析

  • 未过滤文件类型:filepath.Walk会遍历目录下所有条目(包括子目录),代码没有判断当前路径是否是文件就直接打开,可能读取到目录或非CSV文件,这些文件解析后行数不足5行,导致访问s[4]时索引越界。
  • 未检查CSV行列数:即使是CSV文件,也没有提前判断总行数是否≥5,以及目标行的列数是否≥3,直接访问s[4][2]必然会在数据不满足时触发panic。
  • defer位置错误:defer buf.Close()放在if err1 == nil代码块外,当os.Open失败时buf为nil,调用Close()会引发额外panic。
  • 全局变量冗余:全局变量s会被所有遍历到的文件覆盖,且没必要使用全局变量,局部变量更安全。

修正后的代码

package main

import (
    "encoding/csv"
    "fmt"
    "os"
    "path/filepath"
    "strings"
)

func walkfunc(path string, info os.FileInfo, err error) error {
    if err != nil {
        return err
    }

    // 跳过目录,只处理文件
    if info.IsDir() {
        return nil
    }

    // 过滤CSV文件(可选,根据文件名后缀判断)
    if !strings.HasSuffix(strings.ToLower(info.Name()), ".csv") {
        return nil
    }

    buf, err := os.Open(path)
    if err != nil {
        fmt.Printf("open file %s failed: %v\n", path, err)
        return nil
    }
    defer buf.Close() // 放在open成功后,避免nil调用Close

    r := csv.NewReader(buf)
    records, err := r.ReadAll()
    if err != nil {
        fmt.Printf("parse %s as CSV failed: %v\n", path, err)
        return nil
    }

    // 检查行数是否足够
    if len(records) < 5 {
        fmt.Printf("%s has only %d rows, need at least 5\n", path, len(records))
        return nil
    }

    // 检查目标行的列数是否足够
    targetRow := records[4]
    if len(targetRow) < 3 {
        fmt.Printf("row 5 in %s has only %d columns, need at least 3\n", path, len(targetRow))
        return nil
    }

    fmt.Printf("found target value in %s: %v\n", path, targetRow[2])
    // 找到目标文件后可以提前终止遍历
    return filepath.SkipDir
}

func main() {
    const root = "./task/"
    if err := filepath.Walk(root, walkfunc); err != nil && err != filepath.SkipDir {
        fmt.Printf("walk directory failed: %v\n", err)
    }
}

关键修改点

  • 增加目录判断,跳过目录条目。
  • 可选:通过文件名后缀过滤CSV文件(若文件名无后缀,可根据文件内容特征判断)。
  • 将defer buf.Close()移到os.Open成功后,避免nil指针调用。
  • 读取CSV后检查总行数≥5、目标行列数≥3,彻底避免索引越界。
  • 使用局部变量records替代全局变量s,避免数据覆盖。
  • 找到目标文件后返回filepath.SkipDir终止遍历,提升执行效率。
  • 增加错误信息打印,方便调试定位问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 14:50:21