在 Golang 中,是否可能获取调用代码的文件名?

9

我能够获得当前目录的完整路径,现在我想创建一个函数来读取或获取代码执行的文件名。我能够获取文件名,但它返回的是代码编写时的原始文件名:

func GetFileName() string {
    _, fpath, _, ok := runtime.Caller(0)
    if !ok {
        err := errors.New("failed to get filename")
        panic(err)
    }
    filename := filepath.Base(fpath)
    // remove extension
    filename = removeExtension(filename)
    return filename + ".log"
}

我希望做的是获取代码执行时的当前文件名,比如:

我创建了app.go

package my

function getCurrentFileName() string {
    // some code here that will return the filename where this code is executed.
}

当我在不同的位置,例如hello.go文件中调用getCurrentFileName()时,它将返回hello.go

我已经卡在这里一段时间了,正在寻找答案。

2个回答

18

基本上这就是你向 runtime.Caller() 传递的内容:在返回一个条目之前要跳过的堆栈条目数。

如果你像你的代码一样传递 0,那么意味着返回调用 runtime.Caller() 的堆栈条目(也就是你调用 runtime.Caller() 的地方)。传递 1 将会跳过你的函数,并返回调用你的函数的函数:

pc, file, line, ok := runtime.Caller(1)
if ok {
    fmt.Printf("Called from %s, line #%d, func: %v\n",
        file, line, runtime.FuncForPC(pc).Name())
}

示例调用包含此内容的函数(在我的示例中为subplay.A()):

 7   func main() {
 8      // Comment line
 9      subplay.A()
10   }

输出:

Called from /home/icza/gows/src/play/play.go, line #9, func: main.main
我们看到代码打印出play.go在第9行调用了我们的函数,来自于main包的main()函数。

1
这个帮助函数可以提供以下信息:
func Here(skip ...int) (string, string, int, error) {
    sk := 1
    if len(skip) > 0 && skip[0] > 1 {
        sk = skip[0]
    }
    var pc uintptr
    var ok bool
    pc, fileName, fileLine, ok := runtime.Caller(sk)
    if !ok {
        return "", "", 0, fmt.Errorf("N/A")
    }
    fn := runtime.FuncForPC(pc)
    name := fn.Name()
    ix := strings.LastIndex(name, ".")
    if ix > 0 && (ix+1) < len(name) {
        name = name[ix+1:]
    }
    funcName := name
    nd, nf := filepath.Split(fileName)
    fileName = filepath.Join(filepath.Base(nd), nf)
    return funcName, fileName, fileLine, nil
}

“skip”参数是指我们需要向上(调用者链)跳过的调用帧数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接