Golang中ModTime变更问题探讨
Golang中ModTime变更问题探讨 我有一个复制文件并显示复制文件修改时间的函数:
copy(src, dest)
println(getModTime(dest))
如果我稍后尝试获取修改时间,它发生了变化…但文件本身并没有变化。
再次调用 println(getModTime(dest)) 会给出不同的结果…
如果我在复制和打印之间加入休眠,修改时间就会保持一致。
copy(src, dest)
sleep(1 sec)
println(getModTime(dest))
你知道这是为什么吗? 备注:在Linux系统下
2 回复
我认为这是因为在请求修改日期时没有暂停,导致磁盘缓存尚未完全写入磁盘。
更多关于Golang中ModTime变更问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
这是一个典型的文件系统缓存和元数据同步问题。在Linux系统中,文件修改时间等元数据的更新可能存在延迟,导致立即读取时获取到的是缓存中的旧数据。
问题分析
当你在短时间内连续操作文件时:
copy()操作完成,文件系统记录了新的修改时间- 但元数据可能还在内核缓存中,尚未完全同步到磁盘
- 立即调用
getModTime()可能读取到的是缓存中的旧数据
解决方案
方法1:使用文件同步
import (
"os"
"syscall"
)
func copyWithSync(src, dest string) error {
// 复制文件逻辑...
// copy(src, dest)
// 强制文件系统同步
file, err := os.Open(dest)
if err != nil {
return err
}
defer file.Close()
// 同步文件数据到磁盘
file.Sync()
// 同步目录条目
dir, _ := os.OpenFile(".", os.O_RDONLY, 0)
defer dir.Close()
dir.Sync()
return nil
}
方法2:使用stat系统调用直接获取
import (
"syscall"
"time"
)
func getModTimeAccurate(path string) (time.Time, error) {
var stat syscall.Stat_t
err := syscall.Stat(path, &stat)
if err != nil {
return time.Time{}, err
}
return time.Unix(stat.Mtim.Sec, stat.Mtim.Nsec), nil
}
方法3:重试机制
func getModTimeWithRetry(path string, maxRetries int) (time.Time, error) {
for i := 0; i < maxRetries; i++ {
modTime, err := getModTime(path)
if err != nil {
return time.Time{}, err
}
// 短暂延迟后再次检查
time.Sleep(10 * time.Millisecond)
modTime2, err := getModTime(path)
if err != nil {
return time.Time{}, err
}
// 如果两次读取结果一致,返回
if modTime.Equal(modTime2) {
return modTime, nil
}
}
return time.Time{}, fmt.Errorf("mod time inconsistent after %d retries", maxRetries)
}
完整示例
package main
import (
"fmt"
"os"
"time"
)
func reliableCopyAndGetModTime(src, dest string) (time.Time, error) {
// 执行文件复制
err := copyFile(src, dest)
if err != nil {
return time.Time{}, err
}
// 强制同步
file, err := os.Open(dest)
if err != nil {
return time.Time{}, err
}
defer file.Close()
file.Sync()
// 获取修改时间
return getModTime(dest)
}
func copyFile(src, dest string) error {
// 实现文件复制逻辑
// ...
return nil
}
func getModTime(path string) (time.Time, error) {
info, err := os.Stat(path)
if err != nil {
return time.Time{}, err
}
return info.ModTime(), nil
}
问题的根本原因是文件系统为了性能优化而采用的延迟写入机制。通过强制同步或使用更精确的系统调用,可以确保获取到正确的修改时间。

