文件信息操作 #

在实际开发中,经常需要获取文件的各种信息,如文件大小、修改时间、权限等。Go语言的 os 包提供了丰富的文件信息操作功能。

获取文件信息 #

使用 os.Stat #

os.Stat 返回文件的详细信息:

go
package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    fileInfo, err := os.Stat("example.txt")
    if err != nil {
        if os.IsNotExist(err) {
            fmt.Println("文件不存在")
        } else {
            fmt.Println("获取信息失败:", err)
        }
        return
    }
    
    fmt.Println("文件名:", fileInfo.Name())
    fmt.Println("文件大小:", fileInfo.Size(), "字节")
    fmt.Println("修改时间:", fileInfo.ModTime().Format(time.RFC3339))
    fmt.Println("是否为目录:", fileInfo.IsDir())
    fmt.Println("文件权限:", fileInfo.Mode())
}

FileInfo 接口 #

FileInfo 是一个接口,包含以下方法:

go
type FileInfo interface {
    Name() string       // 文件名
    Size() int64        // 文件大小(字节)
    Mode() FileMode     // 文件模式(权限)
    ModTime() time.Time // 修改时间
    IsDir() bool        // 是否为目录
    Sys() any           // 底层数据源
}

检查文件是否存在 #

推荐方式 #

go
package main

import (
    "fmt"
    "os"
)

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

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

详细检查 #

go
package main

import (
    "fmt"
    "os"
)

func checkFile(filename string) {
    info, err := os.Stat(filename)
    if err != nil {
        if os.IsNotExist(err) {
            fmt.Println("文件不存在")
        } else if os.IsPermission(err) {
            fmt.Println("权限不足")
        } else {
            fmt.Println("其他错误:", err)
        }
        return
    }
    
    if info.IsDir() {
        fmt.Println("这是一个目录")
    } else {
        fmt.Println("这是一个文件")
    }
}

func main() {
    checkFile("example.txt")
    checkFile("nonexistent.txt")
}

文件权限操作 #

FileMode 类型 #

FileMode 表示文件模式和权限:

go
package main

import (
    "fmt"
    "os"
)

func main() {
    info, _ := os.Stat("example.txt")
    mode := info.Mode()
    
    fmt.Println("权限字符串:", mode.String())
    fmt.Println("权限数值:", uint32(mode))
    
    if mode&os.ModeDir != 0 {
        fmt.Println("是目录")
    }
    if mode&0400 != 0 {
        fmt.Println("所有者可读")
    }
    if mode&0200 != 0 {
        fmt.Println("所有者可写")
    }
    if mode&0100 != 0 {
        fmt.Println("所有者可执行")
    }
}

修改文件权限 #

go
package main

import (
    "fmt"
    "os"
)

func main() {
    err := os.Chmod("example.txt", 0644)
    if err != nil {
        fmt.Println("修改权限失败:", err)
        return
    }
    
    info, _ := os.Stat("example.txt")
    fmt.Println("新权限:", info.Mode())
}

常用权限值:

权限 数值 说明
0777 所有权限 所有人可读写执行
0755 标准目录权限 所有者全权限,其他人可读可执行
0644 标准文件权限 所有者可读写,其他人只读
0600 私有文件 只有所有者可读写

修改文件时间戳 #

go
package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    accessTime := time.Now()
    modifyTime := time.Now()
    
    err := os.Chtimes("example.txt", accessTime, modifyTime)
    if err != nil {
        fmt.Println("修改时间失败:", err)
        return
    }
    
    info, _ := os.Stat("example.txt")
    fmt.Println("新的修改时间:", info.ModTime())
}

符号链接操作 #

使用 Lstat 获取链接信息 #

LstatStat 的区别在于,当文件是符号链接时,Lstat 返回链接本身的信息:

go
package main

import (
    "fmt"
    "os"
)

func main() {
    linkInfo, err := os.Lstat("symlink")
    if err != nil {
        fmt.Println("获取链接信息失败:", err)
        return
    }
    
    if linkInfo.Mode()&os.ModeSymlink != 0 {
        fmt.Println("这是一个符号链接")
        
        target, err := os.Readlink("symlink")
        if err != nil {
            fmt.Println("读取链接目标失败:", err)
            return
        }
        fmt.Println("链接目标:", target)
    }
}

创建符号链接 #

go
package main

import (
    "fmt"
    "os"
)

func main() {
    err := os.Symlink("original.txt", "link_to_original")
    if err != nil {
        fmt.Println("创建链接失败:", err)
        return
    }
    
    fmt.Println("符号链接创建成功")
}

创建硬链接 #

go
package main

import (
    "fmt"
    "os"
)

func main() {
    err := os.Link("original.txt", "hardlink_to_original")
    if err != nil {
        fmt.Println("创建硬链接失败:", err)
        return
    }
    
    fmt.Println("硬链接创建成功")
}

文件大小格式化 #

go
package main

import (
    "fmt"
    "os"
)

func formatSize(bytes int64) string {
    const (
        KB = 1024
        MB = KB * 1024
        GB = MB * 1024
    )
    
    switch {
    case bytes >= GB:
        return fmt.Sprintf("%.2f GB", float64(bytes)/float64(GB))
    case bytes >= MB:
        return fmt.Sprintf("%.2f MB", float64(bytes)/float64(MB))
    case bytes >= KB:
        return fmt.Sprintf("%.2f KB", float64(bytes)/float64(KB))
    default:
        return fmt.Sprintf("%d B", bytes)
    }
}

func main() {
    info, err := os.Stat("example.txt")
    if err != nil {
        fmt.Println("错误:", err)
        return
    }
    
    fmt.Printf("文件大小: %s\n", formatSize(info.Size()))
}

实用示例:文件信息报告 #

go
package main

import (
    "fmt"
    "os"
    "time"
)

func printFileInfo(filename string) {
    info, err := os.Stat(filename)
    if err != nil {
        fmt.Printf("无法获取 %s 的信息: %v\n", filename, err)
        return
    }
    
    fmt.Println("========== 文件信息报告 ==========")
    fmt.Printf("文件名: %s\n", info.Name())
    fmt.Printf("大小: %d 字节\n", info.Size())
    fmt.Printf("修改时间: %s\n", info.ModTime().Format("2006-01-02 15:04:05"))
    fmt.Printf("权限: %s\n", info.Mode())
    
    mode := info.Mode()
    if mode.IsDir() {
        fmt.Println("类型: 目录")
    } else if mode&os.ModeSymlink != 0 {
        fmt.Println("类型: 符号链接")
    } else {
        fmt.Println("类型: 普通文件")
    }
    
    fmt.Printf("权限详情: ")
    printPermissions(mode)
    fmt.Println()
}

func printPermissions(mode os.FileMode) {
    perms := []struct {
        bit  os.FileMode
        char string
    }{
        {0400, "r"}, {0200, "w"}, {0100, "x"},
        {0040, "r"}, {0020, "w"}, {0010, "x"},
        {0004, "r"}, {0002, "w"}, {0001, "x"},
    }
    
    for _, p := range perms {
        if mode&p.bit != 0 {
            fmt.Print(p.char)
        } else {
            fmt.Print("-")
        }
    }
}

func main() {
    if len(os.Args) < 2 {
        fmt.Println("用法: go run main.go <文件名>")
        return
    }
    
    printFileInfo(os.Args[1])
}

小结 #

函数 用途
os.Stat 获取文件信息(跟随符号链接)
os.Lstat 获取文件信息(不跟随符号链接)
os.IsNotExist 检查是否为"文件不存在"错误
os.IsPermission 检查是否为"权限不足"错误
os.Chmod 修改文件权限
os.Chtimes 修改文件时间戳
os.Symlink 创建符号链接
os.Link 创建硬链接
os.Readlink 读取符号链接目标

掌握文件信息操作是进行高级文件处理的基础,在实际开发中经常用于文件验证、权限检查等场景。