go语言文件操作

Go语言文件操作完整指南

ioutil库的替代方案

Go 1.16开始,ioutil包被弃用,其功能被迁移到以下包:

原ioutil函数新位置说明
ioutil.ReadFile()os.ReadFile()读取整个文件
ioutil.WriteFile()os.WriteFile()写入文件
ioutil.ReadDir()os.ReadDir()读取目录
ioutil.ReadAll()io.ReadAll()读取所有数据
ioutil.TempDir()os.MkdirTemp()创建临时目录
ioutil.TempFile()os.CreateTemp()创建临时文件

1. 基础文件读写操作

1.1 读取整个文件

package main

import (
    "fmt"
    "os"
)

func main() {
    // 新方式:使用 os.ReadFile
    content, err := os.ReadFile("example.txt")
    if err != nil {
        fmt.Printf("读取文件失败: %v\n", err)
        return
    }
    fmt.Printf("文件内容: %s\n", content)
}

1.2 写入文件

package main

import (
    "fmt"
    "os"
)

func main() {
    data := []byte("Hello, Go文件操作!")
    
    // 新方式:使用 os.WriteFile
    err := os.WriteFile("output.txt", data, 0644)
    if err != nil {
        fmt.Printf("写入文件失败: %v\n", err)
        return
    }
    fmt.Println("文件写入成功")
}

2. 文件打开和关闭

2.1 基本文件操作

package main

import (
    "fmt"
    "os"
)

func main() {
    // 打开文件
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Printf("打开文件失败: %v\n", err)
        return
    }
    defer file.Close() // 确保文件被关闭

    // 获取文件信息
    fileInfo, err := file.Stat()
    if err != nil {
        fmt.Printf("获取文件信息失败: %v\n", err)
        return
    }
    
    fmt.Printf("文件名: %s\n", fileInfo.Name())
    fmt.Printf("文件大小: %d 字节\n", fileInfo.Size())
    fmt.Printf("修改时间: %v\n", fileInfo.ModTime())
}

2.2 创建和写入文件

package main

import (
    "fmt"
    "os"
)

func main() {
    // 创建文件(如果存在会截断)
    file, err := os.Create("newfile.txt")
    if err != nil {
        fmt.Printf("创建文件失败: %v\n", err)
        return
    }
    defer file.Close()

    // 写入数据
    data := "这是新创建的文件内容\n"
    _, err = file.WriteString(data)
    if err != nil {
        fmt.Printf("写入失败: %v\n", err)
        return
    }
    
    fmt.Println("文件创建并写入成功")
}

3. 按行读取文件

3.1 使用bufio包逐行读取

package main

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

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Printf("打开文件失败: %v\n", err)
        return
    }
    defer file.Close()

    scanner := bufio.NewScanner(file)
    lineNum := 1
    
    for scanner.Scan() {
        fmt.Printf("第%d行: %s\n", lineNum, scanner.Text())
        lineNum++
    }

    if err := scanner.Err(); err != nil {
        fmt.Printf("读取文件时出错: %v\n", err)
    }
}

3.2 使用bufio.Reader

package main

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

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Printf("打开文件失败: %v\n", err)
        return
    }
    defer file.Close()

    reader := bufio.NewReader(file)
    lineNum := 1

    for {
        line, err := reader.ReadString('\n')
        if err != nil {
            if err == io.EOF {
                if len(line) > 0 {
                    fmt.Printf("第%d行: %s", lineNum, line)
                }
                break
            }
            fmt.Printf("读取错误: %v\n", err)
            break
        }
        fmt.Printf("第%d行: %s", lineNum, line)
        lineNum++
    }
}

4. 文件追加操作

package main

import (
    "fmt"
    "os"
)

func main() {
    // 以追加模式打开文件
    file, err := os.OpenFile("append.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Printf("打开文件失败: %v\n", err)
        return
    }
    defer file.Close()

    // 追加内容
    content := "这是追加的内容\n"
    _, err = file.WriteString(content)
    if err != nil {
        fmt.Printf("写入失败: %v\n", err)
        return
    }
    
    fmt.Println("内容追加成功")
}

5. 目录操作

5.1 读取目录

package main

import (
    "fmt"
    "os"
)

func main() {
    // 新方式:使用 os.ReadDir
    entries, err := os.ReadDir(".")
    if err != nil {
        fmt.Printf("读取目录失败: %v\n", err)
        return
    }

    fmt.Println("当前目录内容:")
    for _, entry := range entries {
        if entry.IsDir() {
            fmt.Printf("[目录] %s\n", entry.Name())
        } else {
            fmt.Printf("[文件] %s\n", entry.Name())
        }
    }
}

5.2 创建目录

package main

import (
    "fmt"
    "os"
)

func main() {
    // 创建单个目录
    err := os.Mkdir("testdir", 0755)
    if err != nil {
        fmt.Printf("创建目录失败: %v\n", err)
    } else {
        fmt.Println("目录创建成功")
    }

    // 创建多级目录
    err = os.MkdirAll("path/to/nested/dir", 0755)
    if err != nil {
        fmt.Printf("创建多级目录失败: %v\n", err)
    } else {
        fmt.Println("多级目录创建成功")
    }
}

6. 文件和目录的判断

package main

import (
    "fmt"
    "os"
)

func main() {
    path := "example.txt"
    
    // 检查文件或目录是否存在
    if _, err := os.Stat(path); err == nil {
        fmt.Printf("%s 存在\n", path)
        
        // 获取详细信息
        info, _ := os.Stat(path)
        
        if info.IsDir() {
            fmt.Printf("%s 是目录\n", path)
        } else {
            fmt.Printf("%s 是文件,大小: %d 字节\n", path, info.Size())
        }
    } else if os.IsNotExist(err) {
        fmt.Printf("%s 不存在\n", path)
    } else {
        fmt.Printf("检查 %s 时出错: %v\n", path, err)
    }
}

7. 临时文件和目录

7.1 创建临时文件

package main

import (
    "fmt"
    "os"
)

func main() {
    // 新方式:使用 os.CreateTemp
    tmpFile, err := os.CreateTemp("", "example_*.txt")
    if err != nil {
        fmt.Printf("创建临时文件失败: %v\n", err)
        return
    }
    defer os.Remove(tmpFile.Name()) // 清理临时文件
    defer tmpFile.Close()

    fmt.Printf("临时文件路径: %s\n", tmpFile.Name())

    // 写入临时文件
    content := "这是临时文件的内容"
    _, err = tmpFile.WriteString(content)
    if err != nil {
        fmt.Printf("写入临时文件失败: %v\n", err)
        return
    }
    
    fmt.Println("临时文件创建并写入成功")
}

7.2 创建临时目录

package main

import (
    "fmt"
    "os"
)

func main() {
    // 新方式:使用 os.MkdirTemp
    tmpDir, err := os.MkdirTemp("", "example_dir_*")
    if err != nil {
        fmt.Printf("创建临时目录失败: %v\n", err)
        return
    }
    defer os.RemoveAll(tmpDir) // 清理临时目录

    fmt.Printf("临时目录路径: %s\n", tmpDir)
}

8. 文件复制

package main

import (
    "fmt"
    "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", "destination.txt")
    if err != nil {
        fmt.Printf("文件复制失败: %v\n", err)
    } else {
        fmt.Println("文件复制成功")
    }
}

9. 文件权限操作

package main

import (
    "fmt"
    "os"
)

func main() {
    filename := "example.txt"
    
    // 修改文件权限
    err := os.Chmod(filename, 0755)
    if err != nil {
        fmt.Printf("修改权限失败: %v\n", err)
        return
    }
    
    // 获取文件信息查看权限
    info, err := os.Stat(filename)
    if err != nil {
        fmt.Printf("获取文件信息失败: %v\n", err)
        return
    }
    
    fmt.Printf("文件权限: %v\n", info.Mode().Perm())
}

10. 文件删除和重命名

package main

import (
    "fmt"
    "os"
)

func main() {
    // 重命名文件
    err := os.Rename("oldname.txt", "newname.txt")
    if err != nil {
        fmt.Printf("重命名失败: %v\n", err)
    } else {
        fmt.Println("文件重命名成功")
    }

    // 删除文件
    err = os.Remove("unwanted.txt")
    if err != nil {
        fmt.Printf("删除文件失败: %v\n", err)
    } else {
        fmt.Println("文件删除成功")
    }

    // 删除目录(包括所有内容)
    err = os.RemoveAll("unwanted_dir")
    if err != nil {
        fmt.Printf("删除目录失败: %v\n", err)
    } else {
        fmt.Println("目录删除成功")
    }
}

11. 文件路径操作

package main

import (
    "fmt"
    "path/filepath"
)

func main() {
    path := "/home/user/documents/file.txt"
    
    fmt.Printf("完整路径: %s\n", path)
    fmt.Printf("目录: %s\n", filepath.Dir(path))
    fmt.Printf("文件名: %s\n", filepath.Base(path))
    fmt.Printf("扩展名: %s\n", filepath.Ext(path))
    
    // 构建路径
    newPath := filepath.Join("home", "user", "documents", "newfile.txt")
    fmt.Printf("构建的路径: %s\n", newPath)
    
    // 获取绝对路径
    absPath, err := filepath.Abs("./example.txt")
    if err == nil {
        fmt.Printf("绝对路径: %s\n", absPath)
    }
}

12. 错误处理最佳实践

package main

import (
    "errors"
    "fmt"
    "os"
)

func safeFileOperation(filename string) error {
    // 检查文件是否存在
    if _, err := os.Stat(filename); os.IsNotExist(err) {
        return fmt.Errorf("文件 %s 不存在", filename)
    }

    // 打开文件
    file, err := os.Open(filename)
    if err != nil {
        return fmt.Errorf("无法打开文件 %s: %w", filename, err)
    }
    defer file.Close()

    // 读取文件
    content, err := io.ReadAll(file)
    if err != nil {
        return fmt.Errorf("读取文件 %s 失败: %w", filename, err)
    }

    fmt.Printf("成功读取文件,大小: %d 字节\n", len(content))
    return nil
}

func main() {
    if err := safeFileOperation("example.txt"); err != nil {
        fmt.Printf("操作失败: %v\n", err)
        
        // 检查特定错误类型
        if errors.Is(err, os.ErrNotExist) {
            fmt.Println("这是一个文件不存在的错误")
        }
    }
}

总结

主要变化点:

  1. ioutil.ReadFile()os.ReadFile()
  2. ioutil.WriteFile()os.WriteFile()
  3. ioutil.ReadDir()os.ReadDir()
  4. ioutil.ReadAll()io.ReadAll()
  5. ioutil.TempDir()os.MkdirTemp()
  6. ioutil.TempFile()os.CreateTemp()

这些新的API提供了更好的性能和更清晰的包结构。建议在新项目中直接使用新的API,旧项目可以逐步迁移。

上一篇