gfile_scan.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. // Copyright 2017-2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gfile
  7. import (
  8. "github.com/gogf/gf/errors/gerror"
  9. "github.com/gogf/gf/text/gstr"
  10. "os"
  11. "path/filepath"
  12. "sort"
  13. )
  14. const (
  15. // Max recursive depth for directory scanning.
  16. gMAX_SCAN_DEPTH = 100000
  17. )
  18. // ScanDir returns all sub-files with absolute paths of given <path>,
  19. // It scans directory recursively if given parameter <recursive> is true.
  20. //
  21. // The pattern parameter <pattern> supports multiple file name patterns,
  22. // using the ',' symbol to separate multiple patterns.
  23. func ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
  24. isRecursive := false
  25. if len(recursive) > 0 {
  26. isRecursive = recursive[0]
  27. }
  28. list, err := doScanDir(0, path, pattern, isRecursive, nil)
  29. if err != nil {
  30. return nil, err
  31. }
  32. if len(list) > 0 {
  33. sort.Strings(list)
  34. }
  35. return list, nil
  36. }
  37. // ScanDirFunc returns all sub-files with absolute paths of given <path>,
  38. // It scans directory recursively if given parameter <recursive> is true.
  39. //
  40. // The pattern parameter <pattern> supports multiple file name patterns, using the ','
  41. // symbol to separate multiple patterns.
  42. //
  43. // The parameter <recursive> specifies whether scanning the <path> recursively, which
  44. // means it scans its sub-files and appends the files path to result array if the sub-file
  45. // is also a folder. It is false in default.
  46. //
  47. // The parameter <handler> specifies the callback function handling each sub-file path of
  48. // the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
  49. // string, or else it appends the sub-file path to result slice.
  50. func ScanDirFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
  51. list, err := doScanDir(0, path, pattern, recursive, handler)
  52. if err != nil {
  53. return nil, err
  54. }
  55. if len(list) > 0 {
  56. sort.Strings(list)
  57. }
  58. return list, nil
  59. }
  60. // ScanDirFile returns all sub-files with absolute paths of given <path>,
  61. // It scans directory recursively if given parameter <recursive> is true.
  62. //
  63. // The pattern parameter <pattern> supports multiple file name patterns,
  64. // using the ',' symbol to separate multiple patterns.
  65. //
  66. // Note that it returns only files, exclusive of directories.
  67. func ScanDirFile(path string, pattern string, recursive ...bool) ([]string, error) {
  68. isRecursive := false
  69. if len(recursive) > 0 {
  70. isRecursive = recursive[0]
  71. }
  72. list, err := doScanDir(0, path, pattern, isRecursive, func(path string) string {
  73. if IsDir(path) {
  74. return ""
  75. }
  76. return path
  77. })
  78. if err != nil {
  79. return nil, err
  80. }
  81. if len(list) > 0 {
  82. sort.Strings(list)
  83. }
  84. return list, nil
  85. }
  86. // ScanDirFileFunc returns all sub-files with absolute paths of given <path>,
  87. // It scans directory recursively if given parameter <recursive> is true.
  88. //
  89. // The pattern parameter <pattern> supports multiple file name patterns, using the ','
  90. // symbol to separate multiple patterns.
  91. //
  92. // The parameter <recursive> specifies whether scanning the <path> recursively, which
  93. // means it scans its sub-files and appends the files path to result array if the sub-file
  94. // is also a folder. It is false in default.
  95. //
  96. // The parameter <handler> specifies the callback function handling each sub-file path of
  97. // the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
  98. // string, or else it appends the sub-file path to result slice.
  99. //
  100. // Note that the parameter <path> for <handler> is not a directory but a file.
  101. // It returns only files, exclusive of directories.
  102. func ScanDirFileFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
  103. list, err := doScanDir(0, path, pattern, recursive, func(path string) string {
  104. if IsDir(path) {
  105. return ""
  106. }
  107. return handler(path)
  108. })
  109. if err != nil {
  110. return nil, err
  111. }
  112. if len(list) > 0 {
  113. sort.Strings(list)
  114. }
  115. return list, nil
  116. }
  117. // doScanDir is an internal method which scans directory and returns the absolute path
  118. // list of files that are not sorted.
  119. //
  120. // The pattern parameter <pattern> supports multiple file name patterns, using the ','
  121. // symbol to separate multiple patterns.
  122. //
  123. // The parameter <recursive> specifies whether scanning the <path> recursively, which
  124. // means it scans its sub-files and appends the files path to result array if the sub-file
  125. // is also a folder. It is false in default.
  126. //
  127. // The parameter <handler> specifies the callback function handling each sub-file path of
  128. // the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
  129. // string, or else it appends the sub-file path to result slice.
  130. func doScanDir(depth int, path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
  131. if depth >= gMAX_SCAN_DEPTH {
  132. return nil, gerror.Newf("directory scanning exceeds max recursive depth: %d", gMAX_SCAN_DEPTH)
  133. }
  134. list := ([]string)(nil)
  135. file, err := os.Open(path)
  136. if err != nil {
  137. return nil, err
  138. }
  139. defer file.Close()
  140. names, err := file.Readdirnames(-1)
  141. if err != nil {
  142. return nil, err
  143. }
  144. var (
  145. filePath = ""
  146. patterns = gstr.SplitAndTrim(pattern, ",")
  147. )
  148. for _, name := range names {
  149. filePath = path + Separator + name
  150. if IsDir(filePath) && recursive {
  151. array, _ := doScanDir(depth+1, filePath, pattern, true, handler)
  152. if len(array) > 0 {
  153. list = append(list, array...)
  154. }
  155. }
  156. // Handler filtering.
  157. if handler != nil {
  158. filePath = handler(filePath)
  159. if filePath == "" {
  160. continue
  161. }
  162. }
  163. // If it meets pattern, then add it to the result list.
  164. for _, p := range patterns {
  165. if match, err := filepath.Match(p, name); err == nil && match {
  166. filePath = Abs(filePath)
  167. if filePath != "" {
  168. list = append(list, filePath)
  169. }
  170. }
  171. }
  172. }
  173. return list, nil
  174. }