Deliri
Deliri

Reputation: 126

FilePaths in Go

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

Answers (2)

topskip
topskip

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

Nick Craig-Wood
Nick Craig-Wood

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

Related Questions