Golang 文件操作指南Golang 的文件操作主要依赖 os 和 io 包,通过 os.File、io.Reader、io.Writer 以及 os 包中的函数实现文件创建、读写和目录遍历等操作。
核心概念
- os.File:代表一个打开的文件
- io.Reader:用于读取数据的接口
- io.Writer:用于写入数据的接口
- os 包函数:如 Create、Open、Mkdir 等
基本文件操作
1. 创建文件package mainimport ( "fmt" "os")func main() { file, err := os.Create("example.txt") if err != nil { fmt.Println("创建文件失败:", err) return } defer file.Close() // 确保文件关闭 fmt.Println("文件创建成功!")}- 使用 os.Create 创建文件
- 必须检查错误并处理
- 使用 defer file.Close() 确保文件关闭
2. 写入文件package mainimport ( "fmt" "os")func main() { file, err := os.Create("example.txt") if err != nil { fmt.Println("创建文件失败:", err) return } defer file.Close() // 方法1:使用 Write 写入字节 data := []byte("Hello, Golang file operation!n") n, err := file.Write(data) if err != nil { fmt.Println("写入文件失败:", err) return } fmt.Printf("成功写入 %d 字节n", n) // 方法2:使用 WriteString 写入字符串 n, err = file.WriteString("Another line of text.n") if err != nil { fmt.Println("WriteString 失败:", err) return } fmt.Printf("成功写入 %d 字节 (WriteString)n", n)}- file.Write 接受字节切片作为输入
- file.WriteString 直接写入字符串更方便
- 每次写入后检查错误
3. 读取文件package mainimport ( "fmt" "io" "os")func main() { file, err := os.Open("example.txt") if err != nil { fmt.Println("打开文件失败:", err) return } defer file.Close() buffer := make([]byte, 1024) // 创建缓冲区 n, err := file.Read(buffer) if err != nil && err != io.EOF { // 处理文件结束错误 fmt.Println("读取文件失败:", err) return } fmt.Printf("读取了 %d 字节n", n) fmt.Println(string(buffer[:n])) // 转换为字符串打印}- 使用 os.Open 打开文件
- 创建缓冲区存储读取数据
- file.Read 返回读取的字节数
- 处理 io.EOF 表示文件结束
高级文件操作
1. 目录遍历package mainimport ( "fmt" "os" "path/filepath")func main() { root := "." // 从当前目录开始 err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { fmt.Println("访问出错:", err) return err } fmt.Println(path) return nil }) if err != nil { fmt.Println("遍历目录失败:", err) }}- filepath.Walk 递归遍历目录树
- 回调函数处理每个文件/目录
- 参数包括路径、文件信息和错误
2. 高效读取大文件package mainimport ( "bufio" "fmt" "os")func main() { file, err := os.Open("large_file.txt") if err != nil { fmt.Println("打开文件失败:", err) return } defer file.Close() reader := bufio.NewReader(file) for { line, err := reader.ReadString('n') if err != nil { if err != io.EOF { fmt.Println("读取行失败:", err) } break // 文件结束或错误 } fmt.Println(line) }}- 使用 bufio.NewReader 创建缓冲读取器
- ReadString 逐行读取
- 避免一次性加载大文件到内存
错误处理最佳实践
package mainimport ( "fmt" "os")func writeFile(filename string, data []byte) error { file, err := os.Create(filename) if err != nil { return fmt.Errorf("创建文件失败: %w", err) // 包裹原始错误 } defer func() { if closeErr := file.Close(); closeErr != nil { fmt.Println("关闭文件失败:", closeErr) // 记录但不中断 } }() _, err = file.Write(data) if err != nil { return fmt.Errorf("写入文件失败: %w", err) } return nil}func main() { err := writeFile("output.txt", []byte("This is some data.n")) if err != nil { fmt.Println("发生错误:", err) } else { fmt.Println("文件写入成功!") }}- 检查每个可能出错的步骤
- 使用 defer 确保资源释放
- 使用 fmt.Errorf 和 %w 包裹错误
- 记录错误但不中断主流程
检查文件/目录是否存在
package mainimport ( "fmt" "os")func main() { _, err := os.Stat("myfile.txt") if err != nil { if os.IsNotExist(err) { fmt.Println("文件不存在") } else { fmt.Println("发生错误:", err) } } else { fmt.Println("文件存在") }}- 使用 os.Stat 获取文件信息
- os.IsNotExist 判断文件是否存在
- 处理其他可能的错误
这些操作涵盖了 Golang 中文件和目录操作的主要场景,遵循这些模式可以编写出健壮、高效的文件处理代码。