5

For the below code:

package main

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

func main() {
    b, err := ioutil.ReadFile("shakespeare.txt")

    if err != nil {
        fmt.Print(err)
    }

    str := string(b)

    text := strings.Split(str, " ")
    fmt.Print(len(text))
}

Below is the error:

code$
code$
code$ ls src/github.com/myhub/cs61a/
caching  counters  expressions  gomap  lab_00  Main.go  Readme.md  shakespeare.txt
code$ 
code$ go run src/github.com/myhub/cs61a/Main.go 
open shakespeare.txt: no such file or directory1code$ 
code$ 
code$ 

How to refer a text file located in same directory location of Main.go?

overexchange
  • 15,768
  • 30
  • 152
  • 347
  • Note that your should literally _never_ run your application with `go run `. Never. Either use `go run ` or `go run ` if you insist on not using the normal `go build` followed by `./` way. – Volker May 01 '20 at 06:26

1 Answers1

10

One problem with running a Go program with the go run command is that the directory of the built executable binary is not in the same directory where your "Main.go" file is located.

For instance, here's a program which prints the directory of the binary:

func main() {
        dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
        if err != nil {
                log.Fatal(err)
        }

        fmt.Println(dir)
}

This outputs on my laptop:

go run Main.go
/var/folders/2v/7n_r3hf539x6f6kf0m2zn5z40000gp/T/go-build855783190/b001/exe

You can build the binary first and have it placed in the same directory as your file.

go build -o myapp Main.go

Now we can print the actual directory where the binary lives:

./myapp
/Users/james/Desktop

If you need to hardcode the name of the file in your program and assume it lives in the same directory as your binary, you can now do this:

func main() {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
        log.Fatal(err)
    }

    path := filepath.Join(dir, "shakespeare.txt")
    b, err := ioutil.ReadFile(path)
    if err != nil {
        log.Fatal(err)
    }

    str := string(b)
    text := strings.Split(str, " ")
    fmt.Println(len(text))
}

Again, build then run the binary (I just added two words in my test file named "shakespeare.txt").

go build -o myapp Main.go
./myapp
2

Another option is to have your program accept the path of the file to read as an argument. This way it doesn't matter where your binary or your file lives since you pass that in directly.

func main() {
        b, err := ioutil.ReadFile(os.Args[1])
        if err != nil {
                log.Fatal(err)
        }

        str := string(b)
        text := strings.Split(str, " ")
        fmt.Println(len(text))
}

You can run this with go run or build it first as before:

go run Main.go ~/Desktop/shakespeare.txt
2
James
  • 4,599
  • 2
  • 19
  • 27