Go 中的文件路径
FilePaths in Go
这是 Mark Summerfield 在 Go 中编程的示例。
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var britishAmerican = "british-american.txt"
func init() {
dir, _ := filepath.Split(os.Args[0])
britishAmerican = filepath.Join(dir, britishAmerican)
}
func main() {
rawBytes, err := ioutil.ReadFile(britishAmerican)
if err != nil {
fmt.Println(err)
}
text := string(rawBytes)
usForBritish := make(map[string]string)
lines := strings.Split(text, "\n")
fmt.Println(lines)
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) == 2 {
usForBritish[fields[0]] = fields[1]
}
}
fmt.Println(usForBritish)
}
当我 运行 注释掉带有 init() 函数的这段代码时,它运行得非常好。如果我把它留在里面,我会得到这个错误:
open /var/folders/l6/rdqtyrfd303dw1cz8qvlfcvc0000gn/T/go- build652175567/command-line-arguments/_obj/exe/british-american.txt: no such file or directory exit status 1
我的问题是,为什么 init()
函数没有从适当的目录中抓取文件?
您在 init 函数中更改了变量 britishAmerican
。如果没有 init()
,程序会在当前目录中查找(没有给出路径,只有文件名)。使用 init()
,它会查找可执行文件所在的路径 (os.Args[0]
)。并且 go run main.go
,包含可执行文件的目录不是当前工作目录。
您应该使用 go build
构建二进制文件,然后 运行 它,或者您应该告诉我们您想要实现的目标(如@RoninDev 所写)。
我提到的 MCVE 可能如下所示:
package main
import (
"io/ioutil"
"log"
"os"
"path/filepath"
)
var filename = "foo.txt"
func init() {
// change to true and things break
if false {
dir, _ := filepath.Split(os.Args[0])
filename = filepath.Join(dir, filename)
}
}
func main() {
// requires a file 'foo.txt' in the current directory
_, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
}
它(当然)可以更短,但这应该足以让社区中的其他人看到发生了什么。
在我看来程序在可执行文件所在的目录中需要一个名为 british-american.txt
的文件。
这就是 init()
中的代码所做的 - 它找到可执行文件的路径并构建一个相对于该路径的字典路径。
我从您的错误消息中可以看出您正在使用 go run
到 运行 代码。这会在 /tmp
和 运行 中创建一个临时可执行文件。如果您保留 init()
代码,那么它会在 /tmp
目录中查找字典,但找不到。如果你把init()
代码拿出来,它会在当前目录中寻找字典,它会成功。
如果您想按照作者的意图使用它,请使用 go build
构建一个二进制文件,然后 运行 它 - 这会起作用。
这是 Mark Summerfield 在 Go 中编程的示例。
package main
import (
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
)
var britishAmerican = "british-american.txt"
func init() {
dir, _ := filepath.Split(os.Args[0])
britishAmerican = filepath.Join(dir, britishAmerican)
}
func main() {
rawBytes, err := ioutil.ReadFile(britishAmerican)
if err != nil {
fmt.Println(err)
}
text := string(rawBytes)
usForBritish := make(map[string]string)
lines := strings.Split(text, "\n")
fmt.Println(lines)
for _, line := range lines {
fields := strings.Fields(line)
if len(fields) == 2 {
usForBritish[fields[0]] = fields[1]
}
}
fmt.Println(usForBritish)
}
当我 运行 注释掉带有 init() 函数的这段代码时,它运行得非常好。如果我把它留在里面,我会得到这个错误:
open /var/folders/l6/rdqtyrfd303dw1cz8qvlfcvc0000gn/T/go- build652175567/command-line-arguments/_obj/exe/british-american.txt: no such file or directory exit status 1
我的问题是,为什么 init()
函数没有从适当的目录中抓取文件?
您在 init 函数中更改了变量 britishAmerican
。如果没有 init()
,程序会在当前目录中查找(没有给出路径,只有文件名)。使用 init()
,它会查找可执行文件所在的路径 (os.Args[0]
)。并且 go run main.go
,包含可执行文件的目录不是当前工作目录。
您应该使用 go build
构建二进制文件,然后 运行 它,或者您应该告诉我们您想要实现的目标(如@RoninDev 所写)。
我提到的 MCVE 可能如下所示:
package main
import (
"io/ioutil"
"log"
"os"
"path/filepath"
)
var filename = "foo.txt"
func init() {
// change to true and things break
if false {
dir, _ := filepath.Split(os.Args[0])
filename = filepath.Join(dir, filename)
}
}
func main() {
// requires a file 'foo.txt' in the current directory
_, err := ioutil.ReadFile(filename)
if err != nil {
log.Fatal(err)
}
}
它(当然)可以更短,但这应该足以让社区中的其他人看到发生了什么。
在我看来程序在可执行文件所在的目录中需要一个名为 british-american.txt
的文件。
这就是 init()
中的代码所做的 - 它找到可执行文件的路径并构建一个相对于该路径的字典路径。
我从您的错误消息中可以看出您正在使用 go run
到 运行 代码。这会在 /tmp
和 运行 中创建一个临时可执行文件。如果您保留 init()
代码,那么它会在 /tmp
目录中查找字典,但找不到。如果你把init()
代码拿出来,它会在当前目录中寻找字典,它会成功。
如果您想按照作者的意图使用它,请使用 go build
构建一个二进制文件,然后 运行 它 - 这会起作用。