Private
Public Access
1
0

重构:文件系统模块化架构,优化应用启动流程

This commit is contained in:
2026-01-28 00:28:54 +08:00
parent 4a9b25a505
commit 8c577f70e7
123 changed files with 32030 additions and 967 deletions

View File

@@ -0,0 +1,220 @@
package filesystem
import (
"fmt"
"os"
"syscall"
"time"
)
// Windows API 锁相关函数和常量
var (
modkernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetLastError = modkernel32.NewProc("GetLastError")
procGetProcessId = modkernel32.NewProc("GetProcessId")
)
// 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
}
// CheckFileWithRetry 带重试的文件锁检查
func (c *FileLockChecker) CheckFileWithRetry(path string, maxRetries int, retryInterval time.Duration) error {
for i := 0; i < maxRetries; i++ {
locked, processInfo, err := c.IsFileLocked(path)
if err != nil && !locked {
// 非锁相关的错误,直接返回
return err
}
if !locked {
// 文件未被锁定,可以操作
return nil
}
// 文件被锁定
if i < maxRetries-1 {
// 还有重试机会,等待后重试
time.Sleep(retryInterval)
continue
}
// 最后一次重试失败,返回错误
if processInfo != "" {
return fmt.Errorf("文件被占用: %s", processInfo)
}
return fmt.Errorf("文件被其他程序占用,请关闭相关程序后重试")
}
return fmt.Errorf("文件检查超时")
}
// 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)
)
// BY_HANDLE_FILE_INFORMATION 文件信息结构体
type BY_HANDLE_FILE_INFORMATION struct {
FileAttributes uint32
CreationTime syscall.Filetime
LastAccessTime syscall.Filetime
LastWriteTime syscall.Filetime
VolumeSerialNumber uint32
FileSizeHigh uint32
FileSizeLow uint32
NumberOfLinks uint32
FileIndexHigh uint32
FileIndexLow uint32
}
// 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
}
// 全局文件锁检查器
var globalLockChecker *FileLockChecker
// InitFileLockChecker 初始化全局文件锁检查器
func InitFileLockChecker() {
globalLockChecker = NewFileLockChecker()
}
// GetFileLockChecker 获取全局文件锁检查器
func GetFileLockChecker() *FileLockChecker {
if globalLockChecker == nil {
globalLockChecker = NewFileLockChecker()
}
return globalLockChecker
}