os.fileinfo是描述文件元信息的接口,通过os.stat()、os.lstat()或*os.file.stat()获取,包含name()、size()、mode()、modtime()、isdir()等方法,用于读取文件名、大小、权限、修改时间及类型,但不提供路径或内容访问能力。

os.FileInfo 是什么,它从哪来
os.FileInfo 是一个接口,不是具体类型。你不会直接“创建”它,而是通过 os.Stat()、os.Lstat() 或 *os.File 的 Stat() 方法获得其实例。它封装了文件的基础元信息,比如大小、权限、修改时间等,但不包含内容。
常见误区是以为 os.FileInfo 能读取文件内容或路径——它不能。路径要靠调用方自己保存,内容得另开 os.Open() 或用 ioutil.ReadFile(Go 1.16+ 推荐 os.ReadFile)。
怎么安全获取 os.FileInfo 并避免 panic
最常出错的是忽略错误检查,直接对 nil 的 os.FileInfo 调用方法(比如 fi.Name()),但其实 os.Stat() 失败时返回的是 nil, err,不会 panic;真正 panic 的是后续对 nil 接口值调用方法——Go 运行时会报 panic: runtime error: invalid memory address or nil pointer dereference。
- 务必先检查
err != nil,再使用fi - 不要假设路径存在,尤其是用户输入或配置项中的路径
-
os.Lstat()用于获取符号链接本身的信息(而非目标),需要时才用,否则默认用os.Stat()
示例:
fi, err := os.Stat("/path/to/file")
if err != nil {
log.Printf("stat failed: %v", err)
return
}
fmt.Println("name:", fi.Name())
fmt.Println("size:", fi.Size())
fmt.Println("mode:", fi.Mode())
Mode() 返回值怎么看懂权限和类型
fi.Mode() 返回 os.FileMode,本质是 uint32,但提供了可读方法。它既编码权限(如 0644),也隐含文件类型(普通文件、目录、符号链接等)。
- 用
fi.Mode().IsDir()判断是否为目录,比strings.HasSuffix(fi.Name(), "/")可靠得多 - 权限判断推荐用位运算:例如
fi.Mode()&0111 != 0表示有任意执行权限(对应 Unix 的 user/group/other x 位) -
fi.Mode().String()输出类似-rw-r--r--的字符串,方便调试,但不建议用于逻辑分支(依赖格式易变) - 注意:
fi.Mode().IsRegular()才表示普通文件;IsDir()和IsRegular()互斥,但还有ModeSymlink、ModeNamedPipe等类型需单独判断
Size() 和 ModTime() 在不同文件系统上的行为差异
fi.Size() 对普通文件返回字节数,对目录在大多数系统上返回 0(POSIX 不定义目录大小),Windows 可能返回非零但无意义的值。别拿它判断目录是否为空——应该用 os.ReadDir()。
fi.ModTime() 返回 time.Time,但精度取决于底层文件系统:
- ext4、NTFS 通常支持纳秒级,但 Go 默认只保留到微秒(
time.Now().Round(0)会截断) - FAT32 仅支持 2 秒精度,多次
os.WriteFile()后ModTime()可能不变 - 若需高精度比较,应结合
fi.Sys()获取原始syscall.Stat_t(Unix)或win32.FileInformation(Windows),但跨平台代码中慎用
所以,依赖 ModTime() 做缓存失效或同步逻辑时,记得加个容差(比如 1 秒),尤其面对 USB 设备或网络共享卷。
真正容易被忽略的是:FileInfo 是一次性快照。它不随文件实时更新。如果文件在 Stat 后被其他进程修改,fi.Size() 和 fi.ModTime() 仍反映调用时刻的状态——你需要重新 os.Stat() 才能获取新值。











