Как задать путь к файлу конфигурации?

Добрый день! Можете предложить решения, которые позволят считывать файл config.json после компиляции из любой директории? 

Заранее спасибо!

```go
//Config global
var Config = loadConfig()

//ConfigST struct
type ConfigST struct {
    mutex   sync.RWMutex
    Server  ServerST            `json:"server"`
    Streams map[string]StreamST `json:"streams"`
}

func loadConfig() *ConfigST {
    var tmp ConfigST
    data, err := ioutil.ReadFile("config.json")
    if err != nil {
        log.Fatalln(err)
    }
    err = json.Unmarshal(data, &tmp)
    if err != nil {
        log.Fatalln(err)
    }
    for i, v := range tmp.Streams {
        v.Cl = make(map[string]viewer)
        tmp.Streams[i] = v
    }
    return &tmp
}
```
  • 12 декабря 2024 г. 11:13
Ответы на вопрос 4
Чтобы обеспечить возможность считывания файла конфигурации `config.json` из любой директории после компиляции программы на Go, можно использовать несколько подходов. Вот несколько распространенных решений:

1. **Передача пути в командной строке**:
   Вы можете передавать путь к файлу конфигурации в качестве аргумента командной строки. Используйте пакет `flag` для обработки аргументов.

   пример кода:
   ```go
   package main

   import (
       "flag"
       "encoding/json"
       "io/ioutil"
       "log"
       "sync"
   )

   var Config = loadConfig()

   type ConfigST struct {
       mutex   sync.RWMutex
       Server  ServerST            `json:"server"`
       Streams map[string]StreamST `json:"streams"`
   }

   func loadConfig() *ConfigST {
       var tmp ConfigST
       data, err := ioutil.ReadFile(*configPath)
       if err != nil {
           log.Fatalln(err)
       }
       err = json.Unmarshal(data, &tmp)
       if err != nil {
           log.Fatalln(err)
       }
       for i, v := range tmp.Streams {
           v.Cl = make(map[string]viewer)
           tmp.Streams[i] = v
       }
       return &tmp
   }

   var configPath = flag.String("config", "config.json", "Path to the config file")

   func main() {
       flag.Parse()
       // Продолжайте с остальной логикой программы
   }
   ```

2. **Использование переменной окружения**:
   Можно использовать переменные окружения для указания пути к файлу конфигурации. В функции загрузки конфигурации можно использовать `os.Getenv`.

   пример кода:
   ```go
   package main

   import (
       "encoding/json"
       "io/ioutil"
       "log"
       "os"
       "sync"
   )

   var Config = loadConfig()

   type ConfigST struct {
       mutex   sync.RWMutex
       Server  ServerST            `json:"server"`
       Streams map[string]StreamST `json:"streams"`
   }

   func loadConfig() *ConfigST {
       var tmp ConfigST
       configPath := os.Getenv("CONFIG_PATH")
       if configPath == "" {
           configPath = "config.json"
       }
       data, err := ioutil.ReadFile(configPath)
       if err != nil {
           log.Fatalln(err)
       }
       err = json.Unmarshal(data, &tmp)
       if err != nil {
           log.Fatalln(err)
       }
       for i, v := range tmp.Streams {
           v.Cl = make(map[string]viewer)
           tmp.Streams[i] = v
       }
       return &tmp
   }

   func main() {
       // Продолжайте с остальной логикой программы
   }
   ```

3. **Проверка текущего рабочего каталога**:
   Если требуется держать файл `config.json` в известной относительной директории, можно использовать `os.Getwd()` для получения текущего рабочего каталога и строить путь к конфигурации на основе этого. Тем не менее, этот метод менее гибок, чем передача полного пути или использование переменных окружения.

Выберите подход, который лучше всего соответствует вашим требованиям. В большинстве случаев использование аргументов командной строки или переменных окружения является наиболее универсальным и гибким инструментом для настройки конфигурации приложений.
Если конфиг не должен предоставляться юзером, включи его байты в бинарник. 

import (
	_ "embed"
	"fmt"
)

//go:embed my_config.json
var jsonData []byte

func main() {
	// Выводим встроенные байты
	fmt.Println(string(jsonData))
}
Если есть какая-то определённая директория, в которой лежат конфиги (допустим /config/config.json ), то самым простым и прямолинейным способом, без всяких зависимостей и ухищрений, будет создать в самой директории файл /config/config.go, который будет предоставлять простенький пакет config , и задачей которого будет тупо загружать конфиг из файла в своей директории в структурку с конфигом. И в остальных пакетах будете просто импортировать этот пакет и получать готовые данные. 

Или вот так

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"os"
	"path/filepath"
)

type Config struct {
	Env string `json:"env"`
}

func main() {
	// Получаем текущую директорию
	currentDir, err := os.Getwd()
	if err != nil {
		panic(err)
	}

	// Получаем путь к файлу относительно текущей директории
	filePath := filepath.Join(currentDir, "config/config.json")

	file, err := os.ReadFile(filePath)
	if err != nil {
		log.Fatal(err)
	}
	var config Config
	json.Unmarshal(file, &config)

	fmt.Println(fmt.Sprintf("ENV: %s", config.Env))
}
обычно конфиги пользователей лежат в хомяках пользователей 
типа /home/user/.program/config.json или что-то подобное.
В винде так же.
Определить пользователя, от имени которого запущен бинарник - задачка для детского сада.

Во-первых из переменных окружения, во-вторых для современных многопользовательских систем это классика.
Похожие вопросы