使用Golang+Cobra框架扫描文件路径触发空指针Panic问题
问题描述
使用Go语言的Cobra框架开发一款客户端,用于向传输服务上传文件,需求支持自定义默认下载文件夹。但在检查目标路径是否为存在的文件夹、是否具备写入权限时触发了空指针Panic,场景是在macOS系统中使用拖拽功能输入路径。
原代码
var dldpath string inquire.Query().Input(&dldpath, "Chemin du dossier de téléchargement ", nil).Exec() println("le chemin est : ", dldpath) if len(dldpath) == 0 { fmt.Println(chalk.Red, "Erreur : Vous devez spécifier un dossier à téléverser") os.Exit(0) } dir, err := os.Stat(dldpath) if !dir.IsDir() { fmt.Println(chalk.Red, "Erreur : Le chemin spécifié n'est pas un dossier") os.Exit(0) } if errors.Is(err, os.ErrNotExist) { fmt.Println(chalk.Red, "Erreur : Dossier introuvable") os.Exit(0) } screen.Clear() screen.MoveTopLeft() fmt.Println(chalk.Green, "Dossier de téléchargement par défaut changé avec succès")
错误信息
le chemin est : '/Users/eliezayat/Downloads/bassine wavy.png' panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x1 addr=0x18 pc=0x119b260] goroutine 1 [running]: freetranscli/cmd.glob..func3(0x1370900?, {0x11ef012?, 0x0?, 0x0?}) /Users/eliezayat/Documents/freetranscli/cmd/set.go:44 +0x280 github.com/spf13/cobra.(*Command).execute(0x1370900, {0x13a3d80, 0x0, 0x0}) /Users/eliezayat/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:920 +0x847 github.com/spf13/cobra.(*Command).ExecuteC(0x1370620) /Users/eliezayat/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:1044 +0x3bd github.com/spf13/cobra.(*Command).Execute(...) /Users/eliezayat/go/pkg/mod/github.com/spf13/cobra@v1.6.1/command.go:968 freetranscli/cmd.Execute() /Users/eliezayat/Documents/freetranscli/cmd/root.go:28 +0x25 main.main() /Users/eliezayat/Documents/freetranscli/main.go:8 +0x17 exit status 2
问题根源
错误核心是空指针解引用:当输入路径指向文件而非文件夹时,os.Stat虽不会返回错误,但代码未先处理os.Stat可能的错误(比如路径不存在时err非空,此时dir为nil),就直接调用dir.IsDir(),导致nil指针调用方法触发Panic。
修复方案
调整代码逻辑,先处理错误,再检查路径类型,同时补充写入权限检查:
var dldpath string inquire.Query().Input(&dldpath, "Chemin du dossier de téléchargement ", nil).Exec() println("le chemin est : ", dldpath) if len(dldpath) == 0 { fmt.Println(chalk.Red, "Erreur : Vous devez spécifier un dossier à téléverser") os.Exit(0) } // 先处理os.Stat的错误 dir, err := os.Stat(dldpath) if err != nil { if errors.Is(err, os.ErrNotExist) { fmt.Println(chalk.Red, "Erreur : Dossier introuvable") } else { fmt.Println(chalk.Red, "Erreur lors de la vérification du chemin :", err) } os.Exit(0) } // 检查是否为文件夹 if !dir.IsDir() { fmt.Println(chalk.Red, "Erreur : Le chemin spécifié n'est pas un dossier") os.Exit(0) } // 检查写入权限:尝试创建临时文件验证 tempFile, err := os.CreateTemp(dldpath, "test-write-") if err != nil { fmt.Println(chalk.Red, "Erreur : Aucun droit d'écriture sur le dossier") os.Exit(0) } // 清理临时文件 os.Remove(tempFile.Name()) screen.Clear() screen.MoveTopLeft() fmt.Println(chalk.Green, "Dossier de téléchargement par défaut changé avec succès")
修复要点
- 错误优先处理:调用
os.Stat后先判断err,避免dir为nil时调用方法 - 路径类型校验:确认
dir非空后,再检查是否为文件夹 - 写入权限验证:通过创建临时文件的方式,实际验证文件夹的写入权限(比单纯检查文件模式更可靠)
内容的提问来源于stack exchange,提问作者Elie
相关产品推荐
相关产品推荐

