Go 语言文件处理

在 Go 语言中,文件处理是一个非常重要的功能,它允许我们读取、写入和操作文件。无论是处理配置文件、日志文件,还是进行数据持久化,文件处理都是不可或缺的一部分。

Go 语言提供了丰富的标准库来支持文件处理,包括文件的打开、关闭、读取、写入、追加和删除等操作。

  1. os 是核心库:提供底层文件操作(创建、读写、删除等),大多数场景优先使用。

  2. io 提供通用接口:如 Reader/Writer,可与文件、网络等数据源交互。

  3. bufio 优化性能:通过缓冲减少 I/O 操作次数,适合频繁读写。

  4. ioutil 已弃用:Go 1.16 后其功能迁移到 osio 包。

  5. path/filepath 处理路径:跨平台兼容(Windows/Unix 路径分隔符差异)。

库名主要方法/函数用途说明示例代码
osCreate(name string) (*File, error)创建文件(若存在则清空)file, err := os.Create("test.txt")
Open(name string) (*File, error)只读方式打开文件file, err := os.Open("data.txt")
OpenFile(name string, flag int, perm FileMode) (*File, error)自定义模式打开文件(可指定读写、追加等)file, err := os.OpenFile("log.txt", os.O_APPEND|os.O_WRONLY, 0644)
ReadFile(name string) ([]byte, error)一次性读取整个文件内容(小文件适用)data, err := os.ReadFile("config.json")
WriteFile(name string, data []byte, perm FileMode) error一次性写入文件(覆盖原有内容)err := os.WriteFile("out.txt", []byte("Hello"), 0644)
Remove(name string) error删除文件或空目录err := os.Remove("temp.txt")
Rename(oldpath, newpath string) error重命名或移动文件err := os.Rename("old.txt", "new.txt")
Stat(name string) (FileInfo, error)获取文件信息(大小、权限等)info, err := os.Stat("file.txt")
Mkdir(name string, perm FileMode) error创建单个目录err := os.Mkdir("mydir", 0755)
MkdirAll(path string, perm FileMode) error递归创建多级目录err := os.MkdirAll("path/to/dir", 0755)
ReadDir(name string) ([]DirEntry, error)读取目录内容entries, err := os.ReadDir(".")
ioCopy(dst Writer, src Reader) (written int64, err error)Reader 复制数据到 Writer(如文件复制)io.Copy(dstFile, srcFile)
ReadAll(r Reader) ([]byte, error)Reader 读取所有数据(类似 os.ReadFile,但针对接口)data, err := io.ReadAll(file)
bufioNewScanner(r Reader) *Scanner创建逐行扫描器(适合逐行读取)scanner := bufio.NewScanner(file)
NewReader(rd io.Reader) *Reader创建带缓冲的读取器(提高大文件读取效率)reader := bufio.NewReader(file)
NewWriter(w io.Writer) *Writer创建带缓冲的写入器(提高写入效率)writer := bufio.NewWriter(file)
ioutilReadFile(filename string) ([]byte, error)(已弃用,推荐 os.ReadFiledata, err := ioutil.ReadFile("old.txt")
WriteFile(filename string, data []byte, perm os.FileMode) error(已弃用,推荐 os.WriteFileerr := ioutil.WriteFile("out.txt", data, 0644)
TempDir(dir, pattern string) (name string, err error)(已弃用,推荐 os.MkdirTempdir, err := ioutil.TempDir("", "tmp")
TempFile(dir, pattern string) (f *os.File, err error)(已弃用,推荐 os.CreateTempfile, err := ioutil.TempFile("", "temp-*")
path/filepathJoin(elem ...string) string跨平台安全的路径拼接path := filepath.Join("dir", "file.txt")
Walk(root string, fn WalkFunc) error递归遍历目录树filepath.Walk(".", func(path string, info os.FileInfo, err error) error {...})
Abs(path string) (string, error)获取绝对路径absPath, err := filepath.Abs("file.txt")

不用场景推荐使用方法

场景推荐方法原因
读取小文件os.ReadFile("file.txt")简洁高效,自动处理打开/关闭
逐行读取大文件bufio.NewScanner(file)内存友好,逐行处理
高效写入大量数据bufio.NewWriter(file) + writer.WriteString()缓冲减少磁盘 I/O 次数
递归遍历目录filepath.Walk("/path", callback)自动处理子目录和错误
跨平台路径拼接filepath.Join("dir", "file.txt")自动处理不同操作系统的路径分隔符(/\

文件创建

在 Go 语言中,我们使用 os 包来创建文件。

os.Create 函数用于创建一个文件,并返回一个 *os.File 类型的文件对象。创建文件后,我们通常需要调用 Close 方法来关闭文件,以释放系统资源。

实例

package main

import (
        "log"
        "os"
)

func main() {
        // 创建文件,如果文件已存在会被截断(清空)
        file, err := os.Create("test.txt")
        if err != nil {
                log.Fatal(err)
        }
        defer file.Close() // 确保文件关闭
       
        log.Println("文件创建成功")
}

文件的打开与关闭

在 Go 语言中,我们使用 os 包来打开和关闭文件。

os.Open 函数用于打开一个文件,并返回一个 *os.File 类型的文件对象。打开文件后,我们通常需要调用 Close 方法来关闭文件,以释放系统资源。

打开文件

实例

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()

    fmt.Println("File opened successfully!")
}

在上面的代码中,我们使用 os.Open 打开了一个名为 example.txt 的文件。如果文件打开失败,程序会打印错误信息并退出。defer file.Close() 确保在函数返回前关闭文件。

关闭文件是一个重要的步骤,它可以防止文件描述符泄漏。在 Go 中,我们通常使用 defer 语句来确保文件在函数结束时被关闭。


文件的读取

Go 语言提供了多种读取文件的方式,包括逐行读取、一次性读取整个文件等。我们可以使用 bufio 包来逐行读取文件,或者使用 ioutil 包来一次性读取整个文件。

逐行读取文件

实例

package main

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

func main() {
    file, err := os.Open("example.txt")
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()

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

    if err := scanner.Err(); err != nil {
        fmt.Println("Error reading file:", err)
    }
}

在上面的代码中,我们使用 bufio.NewScanner 创建了一个扫描器,然后通过 scanner.Scan() 逐行读取文件内容,并使用 scanner.Text() 获取每一行的文本。

一次性读取整个文件

实例

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    content, err := ioutil.ReadFile("example.txt")
    if err != nil {
        fmt.Println("Error reading file:", err)
        return
    }

    fmt.Println(string(content))
}

在这个例子中,我们使用 ioutil.ReadFile 一次性读取整个文件的内容,并将其转换为字符串打印出来。


文件的写入

Go 语言也提供了多种写入文件的方式,包括逐行写入、一次性写入等。我们可以使用 os 包来创建和写入文件。

实例

package main

import (
        "log"
        "os"
)

func main() {
        // 方式1:直接写入字符串
        file, err := os.Create("write1.txt")
        if err != nil {
                log.Fatal(err)
        }
        defer file.Close()
       
        file.WriteString("直接写入字符串\n")
       
        // 方式2:写入字节切片
        data := []byte("写入字节切片\n")
        file.Write(data)
       
        // 方式3:使用fmt.Fprintf格式化写入
        fmt.Fprintf(file, "格式化写入: %d\n", 123)
}

逐行写入文件

实例

package main

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

func main() {
    file, err := os.Create("output.txt")
    if err != nil {
        fmt.Println("Error creating file:", err)
        return
    }
    defer file.Close()

    writer := bufio.NewWriter(file)
    fmt.Fprintln(writer, "Hello, World!")
    writer.Flush()
}

在这个例子中,我们使用 os.Create 创建了一个名为 output.txt 的文件,并使用 bufio.NewWriter 创建一个写入器。然后,我们使用 fmt.Fprintln 将字符串写入文件,并调用 writer.Flush() 确保所有数据都被写入文件。

一次性写入文件

实例

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    content := []byte("Hello, World!")
    err := ioutil.WriteFile("output.txt", content, 0644)
    if err != nil {
        fmt.Println("Error writing file:", err)
        return
    }

    fmt.Println("File written successfully!")
}

在这个例子中,我们使用 ioutil.WriteFile 一次性将字节数组写入文件。0644 是文件的权限模式,表示文件所有者可以读写,其他用户只能读取。


文件的追加写入

有时候我们需要在文件的末尾追加内容,而不是覆盖原有内容。Go 语言提供了 os.OpenFile 函数来实现这一功能。

实例

package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.OpenFile("output.txt", os.O_APPEND|os.O_WRONLY, 0644)
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()

    if _, err := file.WriteString("Appended text\n"); err != nil {
        fmt.Println("Error appending to file:", err)
        return
    }

    fmt.Println("Text appended successfully!")
}

在这个例子中,我们使用 os.OpenFile 打开文件,并指定 os.O_APPEND 标志来在文件末尾追加内容。然后,我们使用 file.WriteString 将字符串追加到文件中。


文件的删除

在 Go 语言中,我们可以使用 os.Remove 函数来删除文件。

实例

package main

import (
    "fmt"
    "os"
)

func main() {
    err := os.Remove("output.txt")
    if err != nil {
        fmt.Println("Error deleting file:", err)
        return
    }

    fmt.Println("File deleted successfully!")
}

在这个例子中,我们使用 os.Remove 删除了名为 output.txt 的文件。如果文件删除失败,程序会打印错误信息。


文件信息与操作

获取文件信息

实例

package main

import (
        "fmt"
        "log"
        "os"
)

func main() {
        fileInfo, err := os.Stat("test.txt")
        if err != nil {
                log.Fatal(err)
        }
       
        fmt.Println("文件名:", fileInfo.Name())
        fmt.Println("文件大小:", fileInfo.Size(), "字节")
        fmt.Println("权限:", fileInfo.Mode())
        fmt.Println("最后修改时间:", fileInfo.ModTime())
        fmt.Println("是目录吗:", fileInfo.IsDir())
}

检查文件是否存在

实例

import (
        "fmt"
        "os"
)

func main() {
        if _, err := os.Stat("test.txt"); os.IsNotExist(err) {
                fmt.Println("文件不存在")
        } else {
                fmt.Println("文件存在")
        }
}

重命名和移动文件

实例

package main

import (
        "log"
        "os"
)

func main() {
        err := os.Rename("old.txt", "new.txt")
        if err != nil {
                log.Fatal(err)
        }
        log.Println("重命名成功")
}

目录操作

创建目录

实例

package main

import (
        "log"
        "os"
)

func main() {
        // 创建单个目录
        err := os.Mkdir("newdir", 0755)
        if err != nil {
                log.Fatal(err)
        }
       
        // 递归创建多级目录
        err = os.MkdirAll("path/to/newdir", 0755)
        if err != nil {
                log.Fatal(err)
        }
}

读取目录内容

实例

package main

import (
        "fmt"
        "log"
        "os"
)

func main() {
        entries, err := os.ReadDir(".")
        if err != nil {
                log.Fatal(err)
        }
       
        for _, entry := range entries {
                info, _ := entry.Info()
                fmt.Printf("%-20s %8d %v\n",
                        entry.Name(),
                        info.Size(),
                        info.ModTime().Format("2006-01-02 15:04:05"))
        }
}

删除目录

实例

package main

import (
        "log"
        "os"
)

func main() {
        // 删除空目录
        err := os.Remove("emptydir")
        if err != nil {
                log.Fatal(err)
        }
       
        // 递归删除目录及其内容
        err = os.RemoveAll("path/to/dir")
        if err != nil {
                log.Fatal(err)
        }
}

高级文件操作

文件复制

实例

package main

import (
        "io"
        "log"
        "os"
)

func main() {
        srcFile, err := os.Open("source.txt")
        if err != nil {
                log.Fatal(err)
        }
        defer srcFile.Close()
       
        dstFile, err := os.Create("destination.txt")
        if err != nil {
                log.Fatal(err)
        }
        defer dstFile.Close()
       
        bytesCopied, err := io.Copy(dstFile, srcFile)
        if err != nil {
                log.Fatal(err)
        }
        log.Printf("复制完成,共复制 %d 字节", bytesCopied)
}

文件追加

实例

package main

import (
        "log"
        "os"
)

func main() {
        file, err := os.OpenFile("log.txt",
                os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
        if err != nil {
                log.Fatal(err)
        }
        defer file.Close()
       
        if _, err := file.WriteString("新的日志内容\n"); err != nil {
                log.Fatal(err)
        }
}

临时文件和目录

实例

package main

import (
        "fmt"
        "log"
        "os"
)

func main() {
        // 创建临时文件
        tmpFile, err := os.CreateTemp("", "example-*.txt")
        if err != nil {
                log.Fatal(err)
        }
        defer os.Remove(tmpFile.Name()) // 清理
       
        fmt.Println("临时文件:", tmpFile.Name())
       
        // 创建临时目录
        tmpDir, err := os.MkdirTemp("", "example-*")
        if err != nil {
                log.Fatal(err)
        }
        defer os.RemoveAll(tmpDir) // 清理
       
        fmt.Println("临时目录:", tmpDir)
}