目录操作 #
目录是组织文件的重要方式。Go语言提供了完整的目录操作API,包括创建、删除、遍历等功能。
创建目录 #
创建单个目录 #
go
package main
import (
"fmt"
"os"
)
func main() {
err := os.Mkdir("mydir", 0755)
if err != nil {
fmt.Println("创建目录失败:", err)
return
}
fmt.Println("目录创建成功")
}
创建多级目录 #
使用 MkdirAll 可以一次性创建多级目录:
go
package main
import (
"fmt"
"os"
)
func main() {
err := os.MkdirAll("path/to/my/dir", 0755)
if err != nil {
fmt.Println("创建目录失败:", err)
return
}
fmt.Println("多级目录创建成功")
}
提示:
MkdirAll是幂等的,如果目录已存在,不会返回错误。
删除目录 #
删除空目录 #
go
package main
import (
"fmt"
"os"
)
func main() {
err := os.Remove("mydir")
if err != nil {
fmt.Println("删除失败:", err)
return
}
fmt.Println("目录删除成功")
}
递归删除目录 #
go
package main
import (
"fmt"
"os"
)
func main() {
err := os.RemoveAll("path/to/my/dir")
if err != nil {
fmt.Println("删除失败:", err)
return
}
fmt.Println("目录及其内容已删除")
}
警告:
RemoveAll会删除目录及其所有内容,请谨慎使用!
读取目录内容 #
使用 ReadDir #
go
package main
import (
"fmt"
"os"
)
func main() {
entries, err := os.ReadDir(".")
if err != nil {
fmt.Println("读取目录失败:", err)
return
}
for _, entry := range entries {
typeStr := "文件"
if entry.IsDir() {
typeStr = "目录"
}
info, _ := entry.Info()
fmt.Printf("%-20s %s (%d 字节)\n", entry.Name(), typeStr, info.Size())
}
}
使用 ReadDir 返回的 DirEntry #
DirEntry 接口提供了目录条目的基本信息:
go
package main
import (
"fmt"
"os"
)
func main() {
entries, _ := os.ReadDir(".")
for _, entry := range entries {
fmt.Println("名称:", entry.Name())
fmt.Println("是否为目录:", entry.IsDir())
info, err := entry.Info()
if err == nil {
fmt.Println("大小:", info.Size())
fmt.Println("模式:", info.Mode())
}
fmt.Println("---")
}
}
遍历目录树 #
使用 filepath.WalkDir #
filepath.WalkDir 是遍历目录树的推荐方法:
go
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
root := "."
err := filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
indent := ""
depth := len(filepath.SplitList(path))
for i := 0; i < depth; i++ {
indent += " "
}
typeStr := "📄"
if d.IsDir() {
typeStr = "📁"
}
fmt.Printf("%s%s %s\n", indent, typeStr, d.Name())
return nil
})
if err != nil {
fmt.Println("遍历错误:", err)
}
}
查找特定文件 #
go
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
)
func findFiles(root, ext string) []string {
var files []string
filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() && strings.HasSuffix(d.Name(), ext) {
files = append(files, path)
}
return nil
})
return files
}
func main() {
goFiles := findFiles(".", ".go")
fmt.Println("Go源文件:")
for _, f := range goFiles {
fmt.Println(" ", f)
}
}
跳过特定目录 #
go
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
skipDirs := map[string]bool{
".git": true,
"vendor": true,
"node_modules": true,
}
filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() && skipDirs[d.Name()] {
fmt.Println("跳过目录:", d.Name())
return filepath.SkipDir
}
fmt.Println(path)
return nil
})
}
获取当前目录 #
go
package main
import (
"fmt"
"os"
)
func main() {
dir, err := os.Getwd()
if err != nil {
fmt.Println("获取当前目录失败:", err)
return
}
fmt.Println("当前目录:", dir)
}
切换工作目录 #
go
package main
import (
"fmt"
"os"
)
func main() {
originalDir, _ := os.Getwd()
fmt.Println("原始目录:", originalDir)
err := os.Chdir("/tmp")
if err != nil {
fmt.Println("切换目录失败:", err)
return
}
newDir, _ := os.Getwd()
fmt.Println("新目录:", newDir)
os.Chdir(originalDir)
}
创建临时目录 #
go
package main
import (
"fmt"
"os"
"path/filepath"
)
func main() {
dir, err := os.MkdirTemp("", "myapp-")
if err != nil {
fmt.Println("创建临时目录失败:", err)
return
}
fmt.Println("临时目录:", dir)
defer os.RemoveAll(dir)
file, _ := os.Create(filepath.Join(dir, "temp.txt"))
file.WriteString("临时文件内容")
file.Close()
fmt.Println("临时文件已创建")
}
实用示例:目录大小统计 #
go
package main
import (
"fmt"
"os"
"path/filepath"
)
func dirSize(path string) (int64, error) {
var size int64
err := filepath.WalkDir(path, func(_ string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !d.IsDir() {
info, err := d.Info()
if err != nil {
return err
}
size += info.Size()
}
return nil
})
return size, err
}
func formatSize(bytes int64) string {
const (
KB = 1024
MB = KB * 1024
GB = MB * 1024
)
switch {
case bytes >= GB:
return fmt.Sprintf("%.2f GB", float64(bytes)/float64(GB))
case bytes >= MB:
return fmt.Sprintf("%.2f MB", float64(bytes)/float64(MB))
case bytes >= KB:
return fmt.Sprintf("%.2f KB", float64(bytes)/float64(KB))
default:
return fmt.Sprintf("%d B", bytes)
}
}
func main() {
if len(os.Args) < 2 {
fmt.Println("用法: go run main.go <目录>")
return
}
dir := os.Args[1]
size, err := dirSize(dir)
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Printf("目录 %s 大小: %s\n", dir, formatSize(size))
}
实用示例:目录同步复制 #
go
package main
import (
"fmt"
"io"
"os"
"path/filepath"
)
func copyDir(src, dst string) error {
info, err := os.Stat(src)
if err != nil {
return err
}
if err := os.MkdirAll(dst, info.Mode()); err != nil {
return err
}
entries, err := os.ReadDir(src)
if err != nil {
return err
}
for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())
if entry.IsDir() {
if err := copyDir(srcPath, dstPath); err != nil {
return err
}
} else {
if err := copyFile(srcPath, dstPath); err != nil {
return err
}
}
}
return nil
}
func copyFile(src, dst string) error {
srcFile, err := os.Open(src)
if err != nil {
return err
}
defer srcFile.Close()
srcInfo, _ := srcFile.Stat()
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, srcInfo.Mode())
if err != nil {
return err
}
defer dstFile.Close()
_, err = io.Copy(dstFile, srcFile)
return err
}
func main() {
if len(os.Args) < 3 {
fmt.Println("用法: go run main.go <源目录> <目标目录>")
return
}
src := os.Args[1]
dst := os.Args[2]
err := copyDir(src, dst)
if err != nil {
fmt.Println("复制失败:", err)
return
}
fmt.Println("目录复制成功!")
}
小结 #
| 函数 | 用途 |
|---|---|
os.Mkdir |
创建单个目录 |
os.MkdirAll |
创建多级目录 |
os.Remove |
删除空目录或文件 |
os.RemoveAll |
递归删除目录 |
os.ReadDir |
读取目录内容 |
filepath.WalkDir |
遍历目录树 |
os.Getwd |
获取当前工作目录 |
os.Chdir |
切换工作目录 |
os.MkdirTemp |
创建临时目录 |
目录操作是文件系统编程的基础,合理使用这些API可以高效地管理文件和目录结构。