2021-01-17 21:46:25 +08:00
|
|
|
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
2019-07-27 11:34:04 +08:00
|
|
|
//
|
|
|
|
// This Source Code Form is subject to the terms of the MIT License.
|
|
|
|
// If a copy of the MIT was not distributed with this file,
|
|
|
|
// You can obtain one at https://github.com/gogf/gf.
|
|
|
|
|
|
|
|
package gfile
|
|
|
|
|
|
|
|
import (
|
2020-09-02 21:25:02 +08:00
|
|
|
"github.com/gogf/gf/errors/gerror"
|
2020-03-25 23:36:56 +08:00
|
|
|
"github.com/gogf/gf/text/gstr"
|
2019-07-27 11:34:04 +08:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
)
|
|
|
|
|
2020-09-02 21:25:02 +08:00
|
|
|
const (
|
|
|
|
// Max recursive depth for directory scanning.
|
2021-01-17 22:10:45 +08:00
|
|
|
maxScanDepth = 100000
|
2020-09-02 21:25:02 +08:00
|
|
|
)
|
|
|
|
|
2019-07-27 11:34:04 +08:00
|
|
|
// ScanDir returns all sub-files with absolute paths of given <path>,
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
2020-01-08 19:30:56 +08:00
|
|
|
//
|
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns,
|
|
|
|
// using the ',' symbol to separate multiple patterns.
|
2019-07-27 11:34:04 +08:00
|
|
|
func ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
|
2019-08-01 17:12:58 +08:00
|
|
|
isRecursive := false
|
2019-07-27 11:34:04 +08:00
|
|
|
if len(recursive) > 0 {
|
|
|
|
isRecursive = recursive[0]
|
|
|
|
}
|
2020-09-02 21:25:02 +08:00
|
|
|
list, err := doScanDir(0, path, pattern, isRecursive, nil)
|
2020-05-15 21:51:03 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
|
|
sort.Strings(list)
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ScanDirFunc returns all sub-files with absolute paths of given <path>,
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
|
|
|
//
|
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns, using the ','
|
|
|
|
// symbol to separate multiple patterns.
|
|
|
|
//
|
|
|
|
// The parameter <recursive> specifies whether scanning the <path> recursively, which
|
|
|
|
// means it scans its sub-files and appends the files path to result array if the sub-file
|
|
|
|
// is also a folder. It is false in default.
|
|
|
|
//
|
|
|
|
// The parameter <handler> specifies the callback function handling each sub-file path of
|
|
|
|
// the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
|
|
|
|
// string, or else it appends the sub-file path to result slice.
|
|
|
|
func ScanDirFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
|
2020-09-02 21:25:02 +08:00
|
|
|
list, err := doScanDir(0, path, pattern, recursive, handler)
|
2019-07-27 11:34:04 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
|
|
sort.Strings(list)
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ScanDirFile returns all sub-files with absolute paths of given <path>,
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
|
|
|
//
|
2020-01-08 19:30:56 +08:00
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns,
|
|
|
|
// using the ',' symbol to separate multiple patterns.
|
|
|
|
//
|
2019-07-27 11:34:04 +08:00
|
|
|
// Note that it returns only files, exclusive of directories.
|
|
|
|
func ScanDirFile(path string, pattern string, recursive ...bool) ([]string, error) {
|
2019-08-31 18:04:12 +08:00
|
|
|
isRecursive := false
|
2019-07-27 11:34:04 +08:00
|
|
|
if len(recursive) > 0 {
|
|
|
|
isRecursive = recursive[0]
|
|
|
|
}
|
2020-09-02 21:25:02 +08:00
|
|
|
list, err := doScanDir(0, path, pattern, isRecursive, func(path string) string {
|
2020-05-15 21:51:03 +08:00
|
|
|
if IsDir(path) {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return path
|
|
|
|
})
|
2019-07-27 11:34:04 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
|
|
sort.Strings(list)
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
|
2020-09-09 22:26:46 +08:00
|
|
|
// ScanDirFileFunc returns all sub-files with absolute paths of given <path>,
|
|
|
|
// It scans directory recursively if given parameter <recursive> is true.
|
|
|
|
//
|
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns, using the ','
|
|
|
|
// symbol to separate multiple patterns.
|
|
|
|
//
|
|
|
|
// The parameter <recursive> specifies whether scanning the <path> recursively, which
|
|
|
|
// means it scans its sub-files and appends the files path to result array if the sub-file
|
|
|
|
// is also a folder. It is false in default.
|
|
|
|
//
|
|
|
|
// The parameter <handler> specifies the callback function handling each sub-file path of
|
|
|
|
// the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
|
|
|
|
// string, or else it appends the sub-file path to result slice.
|
|
|
|
//
|
|
|
|
// Note that the parameter <path> for <handler> is not a directory but a file.
|
|
|
|
// It returns only files, exclusive of directories.
|
|
|
|
func ScanDirFileFunc(path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
|
|
|
|
list, err := doScanDir(0, path, pattern, recursive, func(path string) string {
|
|
|
|
if IsDir(path) {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return handler(path)
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(list) > 0 {
|
|
|
|
sort.Strings(list)
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
}
|
|
|
|
|
2020-05-15 21:51:03 +08:00
|
|
|
// doScanDir is an internal method which scans directory and returns the absolute path
|
|
|
|
// list of files that are not sorted.
|
2019-07-27 11:34:04 +08:00
|
|
|
//
|
2020-05-15 21:51:03 +08:00
|
|
|
// The pattern parameter <pattern> supports multiple file name patterns, using the ','
|
|
|
|
// symbol to separate multiple patterns.
|
2019-07-27 11:34:04 +08:00
|
|
|
//
|
2020-05-15 21:51:03 +08:00
|
|
|
// The parameter <recursive> specifies whether scanning the <path> recursively, which
|
|
|
|
// means it scans its sub-files and appends the files path to result array if the sub-file
|
|
|
|
// is also a folder. It is false in default.
|
2019-10-31 23:37:33 +08:00
|
|
|
//
|
2020-05-15 21:51:03 +08:00
|
|
|
// The parameter <handler> specifies the callback function handling each sub-file path of
|
|
|
|
// the <path> and its sub-folders. It ignores the sub-file path if <handler> returns an empty
|
|
|
|
// string, or else it appends the sub-file path to result slice.
|
2020-09-02 21:25:02 +08:00
|
|
|
func doScanDir(depth int, path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
|
2021-01-17 22:10:45 +08:00
|
|
|
if depth >= maxScanDepth {
|
|
|
|
return nil, gerror.Newf("directory scanning exceeds max recursive depth: %d", maxScanDepth)
|
2020-09-02 21:25:02 +08:00
|
|
|
}
|
2019-07-27 11:34:04 +08:00
|
|
|
list := ([]string)(nil)
|
|
|
|
file, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
names, err := file.Readdirnames(-1)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-03-25 23:36:56 +08:00
|
|
|
var (
|
|
|
|
filePath = ""
|
|
|
|
patterns = gstr.SplitAndTrim(pattern, ",")
|
|
|
|
)
|
2019-07-27 11:34:04 +08:00
|
|
|
for _, name := range names {
|
|
|
|
filePath = path + Separator + name
|
2020-05-15 21:51:03 +08:00
|
|
|
if IsDir(filePath) && recursive {
|
2020-09-02 21:25:02 +08:00
|
|
|
array, _ := doScanDir(depth+1, filePath, pattern, true, handler)
|
2019-07-27 11:34:04 +08:00
|
|
|
if len(array) > 0 {
|
|
|
|
list = append(list, array...)
|
|
|
|
}
|
|
|
|
}
|
2020-05-15 21:51:03 +08:00
|
|
|
// Handler filtering.
|
|
|
|
if handler != nil {
|
|
|
|
filePath = handler(filePath)
|
|
|
|
if filePath == "" {
|
|
|
|
continue
|
|
|
|
}
|
2019-07-27 11:34:04 +08:00
|
|
|
}
|
|
|
|
// If it meets pattern, then add it to the result list.
|
2019-08-13 13:45:01 +08:00
|
|
|
for _, p := range patterns {
|
|
|
|
if match, err := filepath.Match(p, name); err == nil && match {
|
2019-07-27 11:34:04 +08:00
|
|
|
filePath = Abs(filePath)
|
|
|
|
if filePath != "" {
|
|
|
|
list = append(list, filePath)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list, nil
|
|
|
|
}
|