Using relative file paths in Go as function parameters

77 Views Asked by At

Lets say I have a folder structure like so:

src/
- main.go
data/
- example.csv
csv/
- parse.go
utils/
- mapFields.go

The mapFields function takes in input and output csv files as paramters:

MapFields(csvInPath string, csvOutPath string) {...}

I want to be able to call this mapFields function from any .go file using relative file paths. For example, from main.go:

MapFields("../data/example.csv", "../data/output.csv")

I cannot figure out how to ensure MapFields opens a csv using a path created from the file path of the calling function joined with the relative path of the csv.

I have used this stack overflow post to implement a solution to get the equivalent of __dirname in Node.js, but there is no success.

I'd appreciate any input on this.

2

There are 2 best solutions below

1
m-szalik On

File path is resolved in context of your current working directory.

During development it is usually the root directory of your project. You can check what is your current directory using os.Getwd().

func main() {
    if workingDirectory, err := os.Getwd(); err != nil {
        panic(fmt.Sprintf("cennot get working direcory - %s", err))
    } else {
        fmt.Printf("Working direcory is %s", workingDirectory)
    }
}

For more flexibility consider using environment variable to indicate the root directory for your csv files. if environment variable is not set use filepath.Join(".", "data").

0
nimdrak On

@JimB and @m-szalik write good answers and advices. That looks good enough to solve your problem. But I try to summarize the answers in my style.

Summary

You need to put the input files in the directories aligned with the working directory of the compiled and executed binary file, Rather than the directory of your development environment.

You can run your binary main from your code, using ../data/example.csv in the src folder, in the below file hierarchy. The important thing is where your binary will be executed.

// run main at ./src
➜  src ./main                

// file hierarchy
.
├── data
│   ├── example.csv
│   └── output.csv
└── src
    ├── main
    └── main.go

Definitions we have to know

In short, relative path is depending on the working directory where your compiled and executed binary file runs.

Therefore, JimB said the compiled binary matters.

Absolute path

An absolute or full path points to the same location in a file system, regardless of the current working directory. To do that, it must include the root directory.

Relative path

By contrast, a relative path starts from some given working directory, ...

https://en.wikipedia.org/wiki/Path_(computing)#Absolute_and_relative_paths

Working directory

In computing, the working directory of a process is a directory of a hierarchical file system, if any, dynamically associated with the process. It is sometimes called the current working directory (CWD),

https://en.wikipedia.org/wiki/Working_directory

Simplified example

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Human struct {
    Life string `json:"life"`
}

func main() {
    var human Human
    data, errRead := os.ReadFile("txt/input")
    errUnMarshall := json.Unmarshal(data, &human)

    fmt.Println(errRead)
    fmt.Println(errUnMarshall)
    fmt.Println(human)
}

This code reads input text from its relative path txt/ And its directories and files are like this.

.
└── src
    ├── main
    ├── main.go
    └── txt
        └── input

Case 1

I run main on src/. Then it works. The reason is main's working directory src/ and it corresponds with os.ReadFile("txt/input")

it prints like this. input text contains {"life":"Life is hard"} string.

➜  src ./main                
<nil>
<nil>
{Life is hard}

Case 2

I run main on .. Then it fails. The reason is main's working directory . and it doesn't correspond with os.ReadFile("txt/input")

➜ . ./src/main 
open txt/input: no such file or directory
unexpected end of JSON input
{}

Etc

You can find the working directory is the directory where your binary runs in terminal. The important thing is what directory the program runs at.

If you're using IDE such as IntelliJ, then you can set the working directory at Run/Debug configuration. enter image description here