Reputation: 126
So this is the example from Programming in Go by Mark Summerfield.
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)
}
When I run this code with the init() func commented out, it works perfectly fine. If I leave it in I get this error:
open /var/folders/l6/rdqtyrfd303dw1cz8qvlfcvc0000gn/T/go- build652175567/command-line-arguments/_obj/exe/british-american.txt: no such file or directory exit status 1
My question is, why does the init()
func not grab the file from the appropriate directory?
Upvotes: 0
Views: 1427
Reputation: 17375
You change the variable britishAmerican
in the init function. Without init()
, the program looks in the current directory (no path given, only the file name). With init()
, it looks in the path where the executable is (os.Args[0]
). And with go run main.go
, the directory with the executable is not the current working directory.
You should use go build
to build the binary and then run it, or you should tell us what you want to achieve (as written by @RoninDev).
The MCVE I've mentioned could look like this:
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)
}
}
It can (of course) be even shorter, but this should be enough for the others in the community to see what is going on.
Upvotes: 3
Reputation: 54117
It looks to me like the program is expecting a file called british-american.txt
in the directory that the executable is in.
That is what the code in init()
does - it finds the path the the executable and constructs a path to the dictionary relative to that.
I can see from your error message that you are using go run
to run the code. This makes a temporary executable in /tmp
and runs that. If you leave the init()
code in then it will look for the dictionary in the /tmp
directory and it won't find it. If you take the init()
code out it will look for the dictionary in the current directory and it will succeed.
If you want to use it as the author intended then use go build
to build a binary and then run it - that will work.
Upvotes: 2