ZetCode

Go 文件

最后修改时间 2024 年 4 月 11 日

在本文中,我们将展示如何在 Golang 中处理文件。我们读取文件、写入文件、创建文件、列出文件以及确定它们的大小和修改时间。

要在 Go 中处理文件,我们使用 osioutilfmt 包。

os.Stat 函数返回描述文件的 FileInfo 结构。

Go 检查文件是否存在

在下面的示例中,我们检查给定文件是否存在。

main.go
package main

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

func main() {

    _, err := os.Stat("words.txt")

    if errors.Is(err, os.ErrNotExist) {

        fmt.Println("file does not exist")
    } else {

        fmt.Println("file exists")
    }
}

我们在文件上调用 os.Stat 函数。如果函数返回 os.ErrNotExist 错误,则表示文件不存在。

Go 创建文件

os.Create 函数创建或截断给定文件。如果文件已存在,则将其截断。如果文件不存在,则以 0666 模式创建。

main.go
package main

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

func main() {

    file, err := os.Create("empty.txt")

    defer file.Close()

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("file created")
}

该示例创建一个空文件。

Go 删除文件

os.Remove 删除给定文件。

main.go
package main

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

func main() {

    err := os.Remove("words.txt")

    if err != nil {

        log.Fatal(err)
    }

    fmt.Println("file deleted")
}

该示例删除一个文件。

Go 文件大小

在下面的示例中,我们获取文件大小。

main.go
package main

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

func main() {

    fInfo, err := os.Stat("words.txt")

    if err != nil {

        log.Fatal(err)
    }

    fsize := fInfo.Size()

    fmt.Printf("The file size is %d bytes\n", fsize)
}

首先,我们使用 os.Stat 获取 FileInfo 结构。然后,我们使用 Size 函数从结构中获取文件大小(以字节为单位)。

Go 文件最后修改时间

在下面的示例中,我们获取给定文件的最后修改时间。

main.go
package main

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

func main() {

    fileName := "words.txt"

    fileInfo, err := os.Stat(fileName)

    if err != nil {
        log.Fatal(err)
    }

    mTime := fileInfo.ModTime()

    fmt.Println(mTime)
}

我们使用 FileInfo 结构中的 ModTime 函数获取最后修改时间。

Go 读取文件

ioutil.ReadFile 读取参数指定的文件并返回其内容。该函数一次性读取整个文件;因此,不应将其用于大文件。

main.go
package main

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

func main() {

    content, err := ioutil.ReadFile("words.txt")

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(string(content))
}

在代码示例中,我们读取文本文件的内容并将其打印到控制台。

对于大文件,更合适的方法是逐行读取。这样程序就不会占用大量内存。

main.go
package main

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

func main() {

    f, err := os.Open("words.txt")

    if err != nil {
        log.Fatal(err)
    }

    defer f.Close()

    scanner := bufio.NewScanner(f)

    for scanner.Scan() {

        fmt.Println(scanner.Text())
    }

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

该示例逐行读取文本文件。

f, err := os.Open("words.txt")

os.Open 函数打开指定文件进行读取。如果成功,返回的文件上的函数可用于读取;关联的文件描述符模式为 O_RDONLY

scanner := bufio.NewScanner(f)

bufio.NewScanner 函数返回一个新的 Scanner 用于读取。

for scanner.Scan() {

    fmt.Println(scanner.Text())
}

使用 Scan 函数,我们前进到下一个令牌。我们使用 Text 函数获取文本。在默认模式下,Scan 函数按行前进。

Go 写入文件

ioutil.WriteFile 函数将数据写入指定文件。如果文件不存在,则创建它;否则,在写入之前将其截断。

main.go
package main

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

func main() {

    fileName := "data.txt"

    val := "old\nfalcon\nsky\ncup\nforest\n"
    data := []byte(val)

    err := ioutil.WriteFile(fileName, data, 0644)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("done")
}

该示例将几个词写入文件。

val := "old\nfalcon\nsky\ncup\nforest\n"
data := []byte(val)

我们有一个字符串,从中创建一个字节切片。

err := ioutil.WriteFile(fileName, data, 0644)

我们以 0644 的权限将字节切片写入给定的文件名。

在下一个示例中,我们将字符串切片写入文件。

main.go
package main

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

func main() {

    fileName := "data.txt"

    f, err := os.Create(fileName)

    if err != nil {

        log.Fatal(err)
    }

    defer f.Close()

    words := []string{"sky", "falcon", "rock", "hawk"}

    for _, word := range words {

        _, err := f.WriteString(word + "\n")

        if err != nil {
            log.Fatal(err)
        }
    }

    fmt.Println("done")
}

WriteString 方法将字符串写入文件。

Go 追加到文件

为了追加到文件,我们将 os.O_APPEND 标志包含在 os.OpenFile 函数的标志中。

main.go
package main

import (
    "log"
    "os"
)

func main() {

    fileName := "words.txt"

    f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)

    if err != nil {
        log.Fatal(err)
    }

    defer f.Close()

    if _, err := f.WriteString("cloud\n"); err != nil {

        log.Fatal(err)
    }
}

该示例使用 WriteString 函数将一个词追加到 words.txt 文件。

Go 复制文件

下一个示例复制文件。

main.go
package main

import (
    "io/ioutil"
    "log"
)

func main() {

    src := "words.txt"
    dest := "words2.txt"

    bytesRead, err := ioutil.ReadFile(src)

    if err != nil {
        log.Fatal(err)
    }

    err = ioutil.WriteFile(dest, bytesRead, 0644)

    if err != nil {
        log.Fatal(err)
    }
}

在代码示例中,我们使用 ioutil.ReadFile 读取源文件的内容,并使用 ioutil.WriteFile 将数据写入目标文件。

Go 列出文件

filepath.Walk 遍历文件树,为树中的每个文件或目录(包括根目录)调用指定的函数。该函数会递归地遍历所有子目录。

main.go
package main

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
)

func main() {

    var files []string

    root := "/home/janbodnar/Documents"

    err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {

        if err != nil {

            fmt.Println(err)
            return nil
        }

        if !info.IsDir() && filepath.Ext(path) == ".txt" {
            files = append(files, path)
        }

        return nil
    })

    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file)
    }
}

在代码示例中,我们搜索扩展名为 .txt 的文件。

var files []string

匹配的文件存储在 files 切片中。

root := "/home/janbodnar/Documents"

这是我们开始搜索的根目录。

err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {

filepath.Walk 的第一个参数是根目录。第二个参数是 walk 函数;filepath.Walk 调用该函数来访问每个文件或目录。

if err != nil {

    fmt.Println(err)
    return nil
}

如果出错,则打印错误,但继续在其他地方搜索。

if !info.IsDir() && filepath.Ext(path) == ".txt" {
    files = append(files, path)
}

如果文件不是目录且具有 .txt 扩展名,我们将其追加到 files 切片。

for _, file := range files {
    fmt.Println(file)
}

最后,我们遍历 files 切片并将所有匹配的文件打印到控制台。

来源

Go os 包 - 参考

在本文中,我们处理了 Golang 中的文件。

作者

我叫 Jan Bodnar,是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。至今,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Go 教程