文件与 IO 操作实战

文件操作是编程中最基础也最常用的需求。Go 语言的 io 包设计优雅,通过 io.Reader 和 io.Writer 接口实现了高度的抽象和复用。 1. 文件读取 1.1 一次性读取整个文件 package main import ( "fmt" "os" ) func main() { // 方法一:os.ReadFile (推荐,Go 1.16+) data, err := os.ReadFile("test.txt") if err != nil { panic(err) } fmt.Println(string(data)) // 方法二:ioutil.ReadFile (已废弃,但仍可用) // data, err := ioutil.ReadFile("test.txt") } 1.2 逐行读取(大文件) import ( "bufio" "fmt" "os" ) func main() { file, err := os.Open("large.txt") if err != nil { panic(err) } defer file.Close() // 确保文件关闭 scanner := bufio.NewScanner(file) for scanner.Scan() { line := scanner.Text() fmt.Println(line) } if err := scanner.Err(); err != nil { panic(err) } } 1.3 按块读取 func main() { file, _ := os.Open("data.bin") defer file.Close() buffer := make([]byte, 1024) // 每次读 1KB for { n, err := file.Read(buffer) if err == io.EOF { break // 文件读完 } if err != nil { panic(err) } fmt.Printf("Read %d bytes\n", n) // 处理 buffer[:n] } } 2. 文件写入 2.1 一次性写入 func main() { data := []byte("Hello, World!\n") // 写入文件(会覆盖原文件) // 0644 是文件权限:rw-r--r-- err := os.WriteFile("output.txt", data, 0644) if err != nil { panic(err) } } 2.2 追加写入 func main() { file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, // 追加模式 0644) if err != nil { panic(err) } defer file.Close() file.WriteString("New log entry\n") } 2.3 使用 bufio 缓冲写入 func main() { file, _ := os.Create("output.txt") defer file.Close() writer := bufio.NewWriter(file) for i := 0; i < 1000; i++ { writer.WriteString(fmt.Sprintf("Line %d\n", i)) } writer.Flush() // 重要:将缓冲区内容写入文件 } 3. 文件与目录操作 3.1 检查文件是否存在 func fileExists(path string) bool { _, err := os.Stat(path) return !os.IsNotExist(err) } 3.2 创建目录 // 创建单层目录 os.Mkdir("mydir", 0755) // 创建多层目录(类似 mkdir -p) os.MkdirAll("path/to/mydir", 0755) 3.3 遍历目录 import ( "fmt" "os" "path/filepath" ) func main() { // 方法一:filepath.Walk filepath.Walk(".", func(path string, info os.FileInfo, err error) error { if err != nil { return err } if !info.IsDir() { fmt.Println("File:", path) } return nil }) // 方法二:os.ReadDir (Go 1.16+) entries, _ := os.ReadDir(".") for _, entry := range entries { fmt.Println(entry.Name(), entry.IsDir()) } } 3.4 删除文件/目录 // 删除文件 os.Remove("file.txt") // 删除目录及其所有内容(类似 rm -rf) os.RemoveAll("mydir") 4. io.Copy 文件拷贝 4.1 复制文件 func copyFile(src, dst string) error { source, err := os.Open(src) if err != nil { return err } defer source.Close() destination, err := os.Create(dst) if err != nil { return err } defer destination.Close() // io.Copy 高效复制 _, err = io.Copy(destination, source) return err } 4.2 显示进度的复制 type ProgressReader struct { reader io.Reader total int64 read int64 } func (pr *ProgressReader) Read(p []byte) (int, error) { n, err := pr.reader.Read(p) pr.read += int64(n) // 打印进度 fmt.Printf("\rProgress: %.2f%%", float64(pr.read)/float64(pr.total)*100) return n, err } 5. 网络文件下载 import ( "io" "net/http" "os" ) func downloadFile(url, filepath string) error { // 发起 HTTP GET 请求 resp, err := http.Get(url) if err != nil { return err } defer resp.Body.Close() // 创建文件 out, err := os.Create(filepath) if err != nil { return err } defer out.Close() // 将响应体复制到文件 _, err = io.Copy(out, resp.Body) return err } func main() { downloadFile("https://example.com/file.zip", "file.zip") } 6. io.Reader 和 io.Writer 接口 6.1 理解接口 type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } 实现了这两个接口的类型: ...

2025-06-19 · 3 min · 606 words · Hank