main.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "path/filepath"
  6. "strings"
  7. )
  8. const (
  9. utf8BOMPrefix = "\xEF\xBB\xBF" // UTF-8 BOM 标记
  10. )
  11. func main() {
  12. dirPath := "E:\\f1\\client"
  13. // 验证目录是否存在
  14. if info, err := os.Stat(dirPath); err != nil || !info.IsDir() {
  15. fmt.Printf("Error: %s is not a valid directory\n", dirPath)
  16. os.Exit(1)
  17. }
  18. // 构建屏蔽目录集合,加快查找速度
  19. excludeSet := make(map[string]bool)
  20. excludeSet["Library"] = true
  21. excludeSet["Packages"] = true
  22. excludeSet["Temp"] = true
  23. excludeSet[".git"] = true
  24. // 遍历目录
  25. err := filepath.WalkDir(dirPath, func(path string, d os.DirEntry, err error) error {
  26. if err != nil {
  27. fmt.Fprintf(os.Stderr, "Warning: cannot access %s: %v\n", path, err)
  28. return filepath.SkipDir // 跳过出错目录,而不是完全终止
  29. }
  30. // 检查是否是需要屏蔽的目录
  31. if d.IsDir() && excludeSet[d.Name()] {
  32. return filepath.SkipDir // 跳过当前目录及其子目录
  33. }
  34. // 只处理 .cs 文件(不区分大小写)
  35. if !d.IsDir() && strings.EqualFold(filepath.Ext(path), ".cs") {
  36. hasBOM, err := checkUTF8WithBOM(path)
  37. if err != nil {
  38. fmt.Fprintf(os.Stderr, "Warning: cannot read file %s: %v\n", path, err)
  39. return nil
  40. }
  41. if !hasBOM {
  42. if true {
  43. // 写入模式:转换文件
  44. if err := convertToUTF8WithBOM(path, false); err != nil {
  45. fmt.Fprintf(os.Stderr, "Error converting %s: %v\n", path, err)
  46. } else {
  47. fmt.Printf("Converted: %s\n", path)
  48. }
  49. } else {
  50. // 只读模式:仅输出路径
  51. fmt.Println(path)
  52. }
  53. }
  54. }
  55. return nil
  56. })
  57. if err != nil {
  58. fmt.Fprintf(os.Stderr, "Error walking directory: %v\n", err)
  59. os.Exit(1)
  60. }
  61. }
  62. // 自定义字符串 slice 类型的 flag,支持多次使用
  63. type stringSliceFlag []string
  64. func (s *stringSliceFlag) String() string {
  65. return strings.Join(*s, ",")
  66. }
  67. func (s *stringSliceFlag) Set(value string) error {
  68. *s = append(*s, value)
  69. return nil
  70. }
  71. // checkUTF8WithBOM 检查文件是否以 UTF-8 BOM 开头
  72. func checkUTF8WithBOM(filename string) (bool, error) {
  73. file, err := os.Open(filename)
  74. if err != nil {
  75. return false, fmt.Errorf("failed to open file: %w", err)
  76. }
  77. defer file.Close()
  78. bom := make([]byte, 3)
  79. n, err := file.Read(bom)
  80. if err != nil && err.Error() != "EOF" {
  81. return false, fmt.Errorf("failed to read file: %w", err)
  82. }
  83. if n < 3 {
  84. return false, nil
  85. }
  86. return string(bom) == utf8BOMPrefix, nil
  87. }
  88. // 将文件转换为 UTF-8 with BOM
  89. func convertToUTF8WithBOM(filename string, backup bool) error {
  90. // 读取原始文件内容
  91. content, err := os.ReadFile(filename)
  92. if err != nil {
  93. return fmt.Errorf("failed to read file: %w", err)
  94. }
  95. // 如果文件已经是 UTF-8 with BOM,跳过
  96. if len(content) >= 3 && string(content[:3]) == utf8BOMPrefix {
  97. return nil
  98. }
  99. // 如果需要备份,创建备份文件
  100. if backup {
  101. backupFile := filename + ".bak"
  102. if err := os.WriteFile(backupFile, content, 0644); err != nil {
  103. return fmt.Errorf("failed to create backup: %w", err)
  104. }
  105. }
  106. // 创建临时文件
  107. tempFile := filename + ".tmp"
  108. file, err := os.Create(tempFile)
  109. if err != nil {
  110. return fmt.Errorf("failed to create temp file: %w", err)
  111. }
  112. // 写入 BOM
  113. if _, err := file.WriteString(utf8BOMPrefix); err != nil {
  114. file.Close()
  115. os.Remove(tempFile)
  116. return fmt.Errorf("failed to write BOM: %w", err)
  117. }
  118. // 写入原始内容
  119. if _, err := file.Write(content); err != nil {
  120. file.Close()
  121. os.Remove(tempFile)
  122. return fmt.Errorf("failed to write content: %w", err)
  123. }
  124. file.Close()
  125. // 替换原文件
  126. if err := os.Rename(tempFile, filename); err != nil {
  127. // 如果重命名失败,尝试删除原文件再重命名
  128. os.Remove(filename)
  129. if err := os.Rename(tempFile, filename); err != nil {
  130. return fmt.Errorf("failed to replace original file: %w", err)
  131. }
  132. }
  133. return nil
  134. }