Golang中如何通过runtime.Caller获取相对路径
Golang中如何通过runtime.Caller获取相对路径 我有一个函数,它使用调用者文件路径(来自 runtime.Caller(1) 的 fn)返回新的错误。
但我想要获取相对路径(相对于执行 go build 的目录,也就是 main.go 所在的目录)。
如何优雅地实现这一点?
func NewError(e interface{}) error {
if e != nil {
_, fn, line, _ := runtime.Caller(1)
return fmt.Errorf("[error] %s:%d %v", fn, line, e)
}
return nil
}
更多关于Golang中如何通过runtime.Caller获取相对路径的实战教程也可以访问 https://www.itying.com/category-94-b0.html
使用 os.Args?
它包含启动 Go 程序的所有参数,包括 Go 二进制文件路径(os.Args[0])。
更多关于Golang中如何通过runtime.Caller获取相对路径的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Christophe_Meessen:
initRelative
这将是 main.go 的目录,通过两次使用 filepath.Dir 实现…
func main() {
fmt.Println("hello world")
}
如果将二进制文件移动到其他位置,Go二进制路径可能会改变
但是runtime.Caller返回的函数不会改变
在文件 relative.go 中定义以下内容:
package main
import (
"runtime"
"filepath"
)
func init() {
initRelative()
}
var prefixPath string
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = filepath.Dir(fileName)
}
func relative(path string) return {
if filepath.HasPrefix(path, prefixPath) {
return path[len(prefixPath):]
}
return path
}
这段代码假设文件 relative.go 存储在构建根目录中。您可能需要修改代码以匹配您的具体使用场景。
这比我的代码更好。但是relative.go在utils包中,而filepath.Dir(filepath.Dir(fileName))只移除了fileName末尾的relative.go。所以prefixPath最终会以"…/utils/“结尾。因此,不以”…/utils/"开头的路径将不会被转换为相对路径。
为了解决这个问题,我建议你将initRelative函数修改如下。
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = fileName[:len(fileName)-len("utils/relative.go")]
}
这应该将prefixPath设置为你项目的根路径。
感谢!
utils/relative.go
package utils
import (
"path/filepath"
"runtime"
"strings"
)
func init() {
initRelative()
}
var prefixPath string
func initRelative() {
_, fileName, _, _ := runtime.Caller(0)
prefixPath = filepath.ToSlash(filepath.Dir(filepath.Dir(fileName))) + "/"
}
func relative(path string) string {
return strings.TrimPrefix(filepath.ToSlash(path), prefixPath)
}
utils/functions.go
package utils
import (
"fmt"
"os"
"runtime"
)
// NewError :
func NewError(e interface{}) error {
if e != nil {
_, fn, line, _ := runtime.Caller(1)
return fmt.Errorf("[error] %s:%d %v", relative(fn), line, e)
}
return nil
}
更新:
使用 filepath.ToSlash(跨平台)
在Go中,要获取相对于构建目录的路径,可以通过比较runtime.Caller返回的绝对路径与构建时的当前工作目录来实现。以下是实现方法:
import (
"fmt"
"path/filepath"
"runtime"
"os"
)
// 获取构建时的当前工作目录(通常是main.go所在目录)
var buildDir string
func init() {
// 获取可执行文件所在目录
exePath, err := os.Executable()
if err != nil {
buildDir, _ = os.Getwd()
return
}
buildDir = filepath.Dir(exePath)
}
func NewError(e interface{}) error {
if e != nil {
_, fn, line, _ := runtime.Caller(1)
// 获取相对于构建目录的路径
relPath, err := filepath.Rel(buildDir, fn)
if err != nil {
// 如果无法获取相对路径,回退到文件名
relPath = filepath.Base(fn)
}
return fmt.Errorf("[error] %s:%d %v", relPath, line, e)
}
return nil
}
这个实现的关键点:
- 在
init函数中获取构建目录路径 - 使用
filepath.Rel()计算相对路径 - 提供错误处理,在无法计算相对路径时回退到文件名
示例使用:
func someFunction() error {
// 假设项目结构:
// /project/main.go
// /project/pkg/utils/errors.go
return NewError("something went wrong")
// 输出: [error] pkg/utils/errors.go:15 something went wrong
}
如果runtime.Caller返回的路径是/home/user/project/pkg/utils/errors.go,而构建目录是/home/user/project,那么相对路径就是pkg/utils/errors.go。
这种方法在大多数情况下都能正常工作,包括在开发环境和生产部署中。

