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