Go中使用flock锁定路径后os.Stat无法正确检测文件存在性
问题根因
该现象是Go生态常用的gofrs/flock库默认行为导致的:调用Lock()方法对不存在的路径加锁时,库会默认携带文件创建标记,自动在目标路径生成空文件后再加锁。因此加锁完成后再执行os.Stat()检测时,文件已经被flock创建,自然不会返回文件不存在的错误。
另外你贴的代码里存在一处笔误:os.IsNotExist(errs)传入的变量名错误,应该传入前面接收到的err变量,该笔误也会导致错误分支判断失效。
可行解决思路
- 方案1:加锁时关闭自动创建文件的配置
不要直接调用无参数的Lock()方法,改用支持自定义锁标记的加锁接口,去掉自动创建文件的LOCK_CREATE标记,文件不存在时加锁操作会直接返回对应错误,你可以在加锁阶段就捕获文件不存在的场景:filePath := filepath.Join(r.path, fmt.Sprintf("%s_event.json", eventId)) fileLock := flock.New(filePath) // 仅加排他锁,不自动创建不存在的文件 err := fileLock.Lock(syscall.LOCK_EX) if err != nil { if os.IsNotExist(err) { return event, EventNotFound{} } return } defer fileLock.Close() // 加锁成功后文件必然存在,可直接执行业务逻辑 - 方案2:加锁后校验文件属性识别自动创建的空文件
如果你需要兼容现有加锁逻辑,可以在加锁后通过文件属性判断是否为flock自动生成的空文件,识别到该场景时清理残留空文件再返回不存在错误:filePath := filepath.Join(r.path, fmt.Sprintf("%s_event.json", eventId)) fileLock := flock.New(filePath) fileLock.Lock() defer fileLock.Close() fileInfo, err := os.Stat(filePath) if err != nil { if os.IsNotExist(err) { return event, EventNotFound{} } return } // flock自动创建的文件大小为0,无业务写入内容,判定为原文件不存在 if fileInfo.Size() == 0 { os.Remove(filePath) // 清理自动生成的垃圾文件 return event, EventNotFound{} } // 后续正常处理已有文件的业务逻辑
注意:优先选择方案1,方案2存在极小的概率把业务正常生成的0字节文件误判为不存在,适合业务逻辑中不会生成0字节事件文件的场景使用。
内容的提问来源于stack exchange,提问作者Maryam
相关产品推荐
相关产品推荐

