Goでファイルを書き込むと書き込み先ファイルが消えているのに読み込める

## 症状
### 準備
以下のようなログラムを作成した．
```go
package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
)

func main() {
	path := "~/.config/tilde-expan/hoge.txt"
	write(path)
	read(path)
}

func write(path string) {
	dir := filepath.Dir(path) // ディレクトリが存在しない場合は作成する
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		err = os.MkdirAll(dir, 0755)
	}

	file, _ := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	defer file.Close()

	fmt.Fprintln(file, "test")
}

func read(path string) {
	file, _ := os.Open(path)
	defer file.Close()

	byteData, _ := io.ReadAll(file)
	content := string(byteData)
	fmt.Println("content = ", content)
}

```

実行の流れは以下の通り．
1. main開始．
1. write呼び出し．
    1. ディレクトリが存在しなければ作成する．
    1. 指定したパスに"test"と書き込む．
1. read呼び出し．
    1. 指定したパスのファイル内容を読み込む．
    1. 読み込んだ内容を出力する．

### 実行結果

以下のように，特にエラーも出ず，書き込んだファイルの中身を表示することができる．
```bash
$ go run main.go
content =  test
```

しかし，保存先であるフォルダに移動しようとしてもフォルダやファイルは存在しない．
```bash
$ cd ~/.config/tilde-expan
cd: no such file or directory: /Users/USERNAME/.config/tilde-expan
$ cat  cd ~/.config/tilde-expan/hoge.txt
cat: cd: No such file or directory
cat: /Users/USERNAME/.config/tilde-expan/hoge.txt: No such file or directory
```

## デバッグ
### プログラム
以下のように，各所でデバッグプリントを入れてみる．
```go
package main

import (
	"fmt"
	"io"
	"os"
	"path/filepath"
)

func main() {
	path := "~/.config/tilde-expan/hoge.txt"
	write(path)
	read(path)
}

func write(path string) {
	dir := filepath.Dir(path) // ディレクトリが存在しない場合は作成する
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		fmt.Println("isNotExist", err)
		err = os.MkdirAll(dir, 0755)
		fmt.Println("MkdirAll", err)
	}

	file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	fmt.Println("OpenFile", err)
	defer file.Close()

	_, err = fmt.Fprintln(file, "test")
	fmt.Println("Fprintln", err)
}

func read(path string) {
	file, err := os.Open(path)
	fmt.Println("Open", err)
	defer file.Close()

	byteData, err := io.ReadAll(file)
	fmt.Println("ReadAll", err)

	content := string(byteData)
	fmt.Println("content = ", content)
}

```

### 結果
各エラー出力は全て`<nil>`．
ついでに`contetn`が2行に増えているので，正しく追記できていることもわかる．

```
$ go run main.go
isNotExist stat ~/.config/tilde-expan: no such file or directory
MkdirAll <nil>
OpenFile <nil>
Fprintln <nil>
Open <nil>
ReadAll <nil>
content =  test
test
```

## 原因
**Goのパス指定はチルダに対応していない．**
これだけだった．

Goのプログラムと同じ場所で`ls`コマンドを実行すると，同じ場所に`~`ディレクトリが生成されている．

```bash
$ ls
README.md    main.go      ~
```

`~`がエクスパンドされないようにパスを`"`で囲んで`cat`コマンドを実行すると，先ほど書き込んだファイルの中身が表示される．

```bash
$ cat "~/.config/tilde-expan/hoge.txt"
test
tes
```

つまり，`~`がホームディレクトリとして認識されず，そのまま`~`ディレクトリだと認識されていた．

## 解決策
**`~`エクスパンド処理を追加する．**
以下のような関数を作る．
```go
func expandTilde(path string) (string, error) {
	if path == "~" || strings.HasPrefix(path, "~/") {
		user, err := user.Current()
		if err != nil {
			return "", err
		}
		if path == "~" {
			return user.HomeDir, nil
		}
		return filepath.Join(user.HomeDir, path[2:]), nil // ~/ を切り取る
	}
	return path, nil
}

``` 

以下のようにして`main`関数に組み込めむ．
```go
func main() {
	path := "~/.config/tilde-expan/hoge.txt"
	actualPath, _ := expandTilde(path)
	fmt.Println("actualPath = ", actualPath)
	write(actualPath)
	read(actualPath)
}
```

パスが正しく変換できていることがわかる．
また，目的通りのパスに保存されていることもわかる．
```bash
$ go run ./main.go
actualPath =  /Users/USERNAME/.config/tilde-expan/hoge.txt
content =  test
$ cat ~/.config/tilde-expan/hoge.txt
test
```

## サンプルプログラム
https://github.com/Tsuyopon-1067/tilde-expand.git