package filesystem import ( "fmt" "os" "syscall" ) // FileLockChecker 文件锁检查器 type FileLockChecker struct{} // NewFileLockChecker 创建文件锁检查器 func NewFileLockChecker() *FileLockChecker { return &FileLockChecker{} } // IsFileLocked 检查文件是否被锁定(被其他进程占用) // 返回: (是否锁定, 错误信息, 错误) func (c *FileLockChecker) IsFileLocked(path string) (bool, string, error) { // 尝试以独占写模式打开文件 file, err := os.OpenFile(path, os.O_RDWR|syscall.O_CREAT, 0666) if err != nil { // 检查是否是锁相关的错误 if isLockError(err) { // 获取占用该文件的进程信息 processInfo, _ := c.getProcessInfo(path) return true, processInfo, nil } return false, "", err } defer file.Close() // 文件可以被打开,说明没有被锁定 return false, "", nil } // isLockError 判断错误是否为文件锁定错误 func isLockError(err error) bool { if err == nil { return false } // 检查错误类型 if os.IsPermission(err) { return true } // Windows 特定错误检查 if pathErr, ok := err.(*os.PathError); ok { errno, ok := pathErr.Err.(syscall.Errno) if ok && (errno == ERROR_SHARING_VIOLATION || errno == ERROR_LOCK_VIOLATION || errno == syscall.ERROR_ACCESS_DENIED) { return true } } errStr := err.Error() lockErrorStrings := []string{ "used by another process", "being used", "access is denied", "could not be opened", "being used by another process", "process cannot access the file", "used by another process", } for _, lockStr := range lockErrorStrings { if contains(errStr, lockStr) { return true } } return false } // getProcessInfo 获取占用文件的进程信息(Windows专用) func (c *FileLockChecker) getProcessInfo(path string) (string, error) { // 在Windows上,使用重启管理器API查询文件占用 // 这里提供简化版本 // 尝试打开文件获取更多信息 handle, err := syscall.Open(path, syscall.O_RDONLY, 0) if err != nil { // 如果打开失败,返回通用提示 return "", nil } defer syscall.Close(handle) // 使用 Windows API 查询文件信息 // 注意:这需要更复杂的 Windows API 调用 // 这里返回简化的提示信息 return "文件正被其他程序使用", nil } // SafeDeleteWithLockCheck 带锁检查的安全删除 func (c *FileLockChecker) SafeDeleteWithLockCheck(path string) error { // 检查文件是否被锁定 locked, processInfo, err := c.IsFileLocked(path) if err != nil && !locked { return err } if locked { if processInfo != "" { return fmt.Errorf("无法删除文件:文件正被其他程序使用\n\n提示:%s\n\n请关闭相关程序后重试", processInfo) } return fmt.Errorf("无法删除文件:文件正被其他程序使用\n\n请关闭相关程序后重试") } // 文件未被锁定,继续删除 return nil } // Windows 特定的结构体和常量 const ( ERROR_LOCK_VIOLATION = 33 // syscall.Errno(33) ERROR_SHARING_VIOLATION = 32 // syscall.Errno(32) ) // contains 检查字符串是否包含子串(不区分大小写) func contains(str, substr string) bool { return len(str) >= len(substr) && (str == substr || len(substr) == 0 || (len(str) > 0 && len(substr) > 0 && containsIgnoreCase(str, substr))) } func containsIgnoreCase(str, substr string) bool { // 简化版小写比较 for i := 0; i <= len(str)-len(substr); i++ { match := true for j := 0; j < len(substr); j++ { c1 := str[i+j] c2 := substr[j] if c1 >= 'A' && c1 <= 'Z' { c1 += 32 } if c2 >= 'A' && c2 <= 'Z' { c2 += 32 } if c1 != c2 { match = false break } } if match { return true } } return false }