Golang中如何在init()函数正确导入并执行ioutil.ReadDir模块

Golang中如何在init()函数正确导入并执行ioutil.ReadDir模块 我有两个模块,ModuleA 和 ModuleB,分别位于不同的文件夹中。ModuleA 中的 main.go 需要导入 ModuleB 中的一个包。在 ModuleB 中该包的 init 函数内部,它会调用 ioutil.ReadDir 并打印当前目录下的所有文件。

我期望在 ModuleA 中导入 ModuleB 时,它应该打印 ModuleB 文件夹下的所有文件。然而,它实际上打印的是 ModuleA 文件夹下的文件。请问如何解决这个问题?

ModuleA 下的 go.mod

module ModuleA

go 1.19

replace ModuleB => ../ModuleB

require ModuleB v0.0.0-00010101000000-000000000000

ModuleA 下的 main.go

package main

import "ModuleB"

func main() {
    math.Add(1, 2)
}

ModuleB 中的 math.go

package math

import (
    "fmt"
    "io/ioutil"
    "log"
)

func init() {
    fmt.Println("init moduleB math")
    // 在此处读取目录
    files, err := ioutil.ReadDir(".")
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name(), file.IsDir())
    }
}

func Add(a, b int) {
    fmt.Println(a + b)
}

文件夹结构

image


更多关于Golang中如何在init()函数正确导入并执行ioutil.ReadDir模块的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

在实际案例中,我尝试将一个配置文件放在ModuleB的目录下,并希望通过导入ModuleB,能够获知该配置文件的内容。

更多关于Golang中如何在init()函数正确导入并执行ioutil.ReadDir模块的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你试图实现什么目标?为什么要在运行时从源代码目录读取文件?也许embed包 - embed - Go Packages能解决你的问题。

dirname 参数 “.” 代表工作目录。你可以通过 os.Getwd() 获取它。你也可以通过 os.Executable() 获取可执行文件的路径。

希望 embed 能解决你的问题。我从未使用过它,所以无法提供任何帮助。否则,你将需要分发配置文件。

在 Go 中,ioutil.ReadDir(".") 会基于当前工作目录执行,而不是基于包所在的目录。当你在 ModuleA 中运行程序时,当前工作目录是 ModuleA 的根目录,因此 ReadDir(".") 读取的是 ModuleA 的文件。

要读取 ModuleB 中包所在的目录,你需要使用 runtime.Calleros.Executable 结合相对路径,但更可靠的方式是使用 embed 包(Go 1.16+)或通过构建时传递路径信息。不过,对于你的需求,最直接的方法是使用 runtime.Caller 获取包文件的路径,然后计算其所在目录。

以下是修改后的 math.go

package math

import (
    "fmt"
    "io/ioutil"
    "log"
    "path/filepath"
    "runtime"
)

func init() {
    fmt.Println("init moduleB math")
    
    // 获取当前包文件的路径
    _, filename, _, ok := runtime.Caller(0)
    if !ok {
        log.Fatal("Failed to get current file path")
    }
    
    // 计算包所在的目录
    pkgDir := filepath.Dir(filename)
    
    // 读取包目录下的文件
    files, err := ioutil.ReadDir(pkgDir)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name(), file.IsDir())
    }
}

func Add(a, b int) {
    fmt.Println(a + b)
}

解释

  1. runtime.Caller(0) 返回当前函数的调用信息,其中第二个返回值是当前文件的完整路径。
  2. filepath.Dir(filename) 获取该文件所在的目录路径。
  3. ioutil.ReadDir(pkgDir) 读取该目录下的文件。

这样,无论 ModuleA 在何处运行,init() 函数都会读取 ModuleB 中 math 包所在目录的文件。

注意:ioutil.ReadDir 在 Go 1.16 后已弃用,建议使用 os.ReadDir。以下是使用 os.ReadDir 的版本:

package math

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
    "runtime"
)

func init() {
    fmt.Println("init moduleB math")
    
    _, filename, _, ok := runtime.Caller(0)
    if !ok {
        log.Fatal("Failed to get current file path")
    }
    
    pkgDir := filepath.Dir(filename)
    
    files, err := os.ReadDir(pkgDir)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        info, _ := file.Info()
        fmt.Println(file.Name(), info.IsDir())
    }
}

func Add(a, b int) {
    fmt.Println(a + b)
}
回到顶部