Skip to content

文件操作

Go 语言提供了丰富的文件操作功能,主要通过 osioioutilbufio 包实现。

📋 学习目标

  • 掌握文件的基本读写操作
  • 理解文件权限和模式
  • 学会目录操作
  • 掌握文件路径处理
  • 了解文件监控
  • 学会文件操作的最佳实践

🎯 文件读取

读取整个文件

go
package main

import (
	"fmt"
	"io/ioutil"
	"log"
)

func main() {
	// 读取整个文件
	data, err := ioutil.ReadFile("file.txt")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("文件内容:\n%s", data)
}

逐行读取

go
package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	file, err := os.Open("file.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}

	if err := scanner.Err(); err != nil {
		log.Fatal(err)
	}
}

分块读取

go
package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	file, err := os.Open("file.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	buf := make([]byte, 1024) // 1KB 缓冲区
	for {
		n, err := file.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		fmt.Print(string(buf[:n]))
	}
}

✍️ 文件写入

写入整个文件

go
package main

import (
	"io/ioutil"
	"log"
)

func main() {
	data := []byte("Hello, Go!")

	err := ioutil.WriteFile("output.txt", data, 0644)
	if err != nil {
		log.Fatal(err)
	}
}

追加写入

go
package main

import (
	"os"
)

func main() {
	file, err := os.OpenFile("output.txt", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	_, err = file.WriteString("追加的内容\n")
	if err != nil {
		log.Fatal(err)
	}
}

使用 bufio 写入

go
package main

import (
	"bufio"
	"os"
)

func main() {
	file, err := os.Create("output.txt")
	if err != nil {
		log.Fatal(err)
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	defer writer.Flush()

	writer.WriteString("第一行\n")
	writer.WriteString("第二行\n")
}

📁 目录操作

创建目录

go
package main

import (
	"os"
)

func main() {
	// 创建单个目录
	err := os.Mkdir("mydir", 0755)
	if err != nil {
		log.Fatal(err)
	}

	// 创建多级目录
	err = os.MkdirAll("path/to/dir", 0755)
	if err != nil {
		log.Fatal(err)
	}
}

读取目录

go
package main

import (
	"fmt"
	"os"
)

func main() {
	entries, err := os.ReadDir(".")
	if err != nil {
		log.Fatal(err)
	}

	for _, entry := range entries {
		fmt.Println(entry.Name(), entry.IsDir())
	}
}

删除文件和目录

go
package main

import (
	"os"
)

func main() {
	// 删除文件
	err := os.Remove("file.txt")
	if err != nil {
		log.Fatal(err)
	}

	// 删除目录(必须为空)
	err = os.Remove("mydir")
	if err != nil {
		log.Fatal(err)
	}

	// 删除目录及其内容
	err = os.RemoveAll("path/to/dir")
	if err != nil {
		log.Fatal(err)
	}
}

🔍 文件信息

获取文件信息

go
package main

import (
	"fmt"
	"os"
)

func main() {
	info, err := os.Stat("file.txt")
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("文件名: %s\n", info.Name())
	fmt.Printf("大小: %d 字节\n", info.Size())
	fmt.Printf("模式: %v\n", info.Mode())
	fmt.Printf("修改时间: %v\n", info.ModTime())
	fmt.Printf("是否目录: %t\n", info.IsDir())
}

检查文件是否存在

go
package main

import (
	"os"
)

func fileExists(filename string) bool {
	_, err := os.Stat(filename)
	return !os.IsNotExist(err)
}

func main() {
	if fileExists("file.txt") {
		fmt.Println("文件存在")
	} else {
		fmt.Println("文件不存在")
	}
}

🛤️ 文件路径

路径操作

go
package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	// 路径拼接
	path := filepath.Join("dir", "subdir", "file.txt")
	fmt.Println(path) // dir/subdir/file.txt (Unix) 或 dir\subdir\file.txt (Windows)

	// 获取目录
	dir := filepath.Dir(path)
	fmt.Println(dir)

	// 获取文件名
	filename := filepath.Base(path)
	fmt.Println(filename)

	// 获取扩展名
	ext := filepath.Ext(path)
	fmt.Println(ext)

	// 获取绝对路径
	absPath, err := filepath.Abs(path)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(absPath)
}

路径匹配

go
package main

import (
	"fmt"
	"path/filepath"
)

func main() {
	// 路径匹配
	matched, err := filepath.Match("*.go", "main.go")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(matched) // true

	// 文件路径匹配
	matched, err = filepath.Match("test/*.go", "test/main.go")
	fmt.Println(matched) // true
}

🔄 文件复制和移动

复制文件

go
package main

import (
	"io"
	"os"
)

func copyFile(src, dst string) error {
	sourceFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer sourceFile.Close()

	destFile, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer destFile.Close()

	_, err = io.Copy(destFile, sourceFile)
	return err
}

func main() {
	err := copyFile("source.txt", "dest.txt")
	if err != nil {
		log.Fatal(err)
	}
}

移动文件

go
package main

import (
	"os"
)

func main() {
	err := os.Rename("old.txt", "new.txt")
	if err != nil {
		log.Fatal(err)
	}
}

🏃‍♂️ 实践应用

文件工具函数

go
package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"
)

// 读取文件所有行
func readLines(filename string) ([]string, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var lines []string
	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		lines = append(lines, scanner.Text())
	}
	return lines, scanner.Err()
}

// 写入文件所有行
func writeLines(lines []string, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	writer := bufio.NewWriter(file)
	for _, line := range lines {
		fmt.Fprintln(writer, line)
	}
	return writer.Flush()
}

func main() {
	lines, err := readLines("input.txt")
	if err != nil {
		log.Fatal(err)
	}

	// 处理行
	for i, line := range lines {
		lines[i] = strings.ToUpper(line)
	}

	err = writeLines(lines, "output.txt")
	if err != nil {
		log.Fatal(err)
	}
}

⚠️ 注意事项

1. 文件权限

go
// 文件权限模式
// 0644: 所有者读写,其他只读
// 0755: 所有者读写执行,其他读执行
// 0600: 仅所有者读写

2. 资源清理

go
// ✅ 总是使用 defer 关闭文件
file, err := os.Open("file.txt")
if err != nil {
	log.Fatal(err)
}
defer file.Close()

3. 错误处理

go
// ✅ 总是检查错误
data, err := ioutil.ReadFile("file.txt")
if err != nil {
	// 处理错误
	return err
}

📚 扩展阅读

⏭️ 下一章节

字符串转换 (strconv) → 学习 Go 语言的字符串转换


💡 提示: 文件操作是程序的基础功能,掌握文件 I/O 对于构建实用程序至关重要!

基于 VitePress 构建