filepath.WalkDirでディレクトリ内を削除するときには注意

# やりたいこと
処理が終わった一時ディレクトリ内を綺麗したい。
でも、親ディレクトリは残しておきたい。
ディレクトリ内は階層が統一されていない。

## 削除したいディレクトリ構造

```
.
├── parentDir1
│   ├── ChildDirA
│   │   └── ChildDirAA
│   └── ChildDirB
└── parentDir2
```

## 試したこと
２つの方法で実施
* ReadDir
* filepath.WalkDir
filepath.WalkDirのほうが処理速度が早いという記事情報あり。

## ReadDirでディレクトリ内を取得

```go
package main

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

func main() {
	dir := "your_directory_path" // 対象のディレクトリパスをここに指定

	err := removeSubdirectories(dir)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Println("All subdirectories removed successfully.")
	}
}

func removeSubdirectories(dir string) error {
	// ディレクトリ内の全てのファイルとサブディレクトリを取得
	files, err := ioutil.ReadDir(dir)
	if err != nil {
		return err
	}

	for _, file := range files {
		if file.IsDir() {
			// サブディレクトリのフルパスを取得
			subDirPath := filepath.Join(dir, file.Name())
            fmt.Printf("Removing directory: %s\n", subDirPath)
			// サブディレクトリを削除
			err = os.RemoveAll(subDirPath)
			if err != nil {
				return err
			}
		}
	}

	return nil
}
```

### 結果
```
Removing directory: /parentDir1/ChildDirA
Removing directory: /parentDir1/ChildDirB
All subdirectories removed successfully.
```

正常に終了。


## filepath.WalkDirで取得

```go
package main

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

func main() {
	dir := "your_directory_path" // 対象のディレクトリパスをここに指定

	err := removeSubdirectoriesUsingWalkDir(dir)
	if err != nil {
		fmt.Printf("Error: %v\n", err)
	} else {
		fmt.Println("All subdirectories removed successfully.")
	}
}

func removeSubdirectoriesUsingWalkDir(root string) error {
	return filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
		if err != nil {
			return err
		}

		// ルートディレクトリそのものは削除しない
		if path == root {
			return nil
		}

		// ディレクトリであれば削除
		if d.IsDir() {
			fmt.Printf("Removing directory: %s\n", path)
			return os.RemoveAll(path)
		}

		return nil
	})
}
```
### 結果
```
Removing directory: /parentDir1/ChildDirA
Error: open /parentDir1/ChildDirA: no such file or directory
```

:::note alert
エラー
/parentDir1/ChildDirAディレクトリがないというエラーが出力されています。
/parentDir1/ChildDirAは削除されていますが、
/parentDir1/ChildDirBは削除されていません。
:::

### 削除部分を以下に変更してみる
削除を実行しないで、nilを返す

```go
// ディレクトリであれば削除
if d.IsDir() {
    fmt.Printf("Removing directory: %s\n", path)
    //return os.RemoveAll(path)
    return nil
}
```

### 結果

```
Removing directory: /parentDir1/ChildDirA
Removing directory: /parentDir1ChildDirA/ChildDirAA
Removing directory: /parentDir1/ChildDirB
All subdirectories removed successfully.
```

どうやら、ChildDirAを削除した後に子ディレクトリを削除しようとしてエラーになっている。
削除の前にディレクトリの存在確認を追加してみる。

```go
func removeSubdirectoriesUsingWalkDir(root string) error {
	return filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
		if err != nil {
			// ディレクトリの存在確認
			if _, err := os.Stat(path); os.IsNotExist(err) {
				fmt.Printf("Directory does not exist: %s\n", path)
				return nil
			}
			return err
		}

		// ルートディレクトリそのものは削除しない
		if path == root {
			return nil
		}

		// ディレクトリであれば削除
		if d.IsDir() {
			fmt.Printf("Removing directory: %s\n", path)
			return os.RemoveAll(path)
		}

		return nil
	})
}
```

### 結果

```
Removing directory: /parentDir1/ChildDirA
Directory does not exist: /parentDir1/ChildDirA
Removing directory: /parentDir1/ChildDirB
Directory does not exist: /parentDir1/ChildDirB
All subdirectories removed successfully.
```

ディレクトリ内の削除は完了
なぜか/parentDir1/ChildDirAと/parentDir1/ChildDirBのそれぞれで存在確認エラー
子ディレクトリを削除するが、その後に子ディレクトリ内の探索が行われる
その為、エラーとなる。

### 解決方法
filepath.WalkDirでディレクトリ内の探索時、エラーの判定後にエラーの種別が存在確認エラーの場合は無視する