mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 11:18:02 +08:00
185 lines
5.9 KiB
Go
185 lines
5.9 KiB
Go
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
|
//
|
|
// 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 (
|
|
"path/filepath"
|
|
"sort"
|
|
|
|
"github.com/gogf/gf/v2/errors/gerror"
|
|
"github.com/gogf/gf/v2/text/gstr"
|
|
)
|
|
|
|
const (
|
|
// Max recursive depth for directory scanning.
|
|
maxScanDepth = 100000
|
|
)
|
|
|
|
// ScanDir 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.
|
|
func ScanDir(path string, pattern string, recursive ...bool) ([]string, error) {
|
|
isRecursive := false
|
|
if len(recursive) > 0 {
|
|
isRecursive = recursive[0]
|
|
}
|
|
list, err := doScanDir(0, path, pattern, isRecursive, nil)
|
|
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) {
|
|
list, err := doScanDir(0, path, pattern, recursive, handler)
|
|
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.
|
|
//
|
|
// The pattern parameter `pattern` supports multiple file name patterns,
|
|
// using the ',' symbol to separate multiple patterns.
|
|
//
|
|
// Note that it returns only files, exclusive of directories.
|
|
func ScanDirFile(path string, pattern string, recursive ...bool) ([]string, error) {
|
|
isRecursive := false
|
|
if len(recursive) > 0 {
|
|
isRecursive = recursive[0]
|
|
}
|
|
list, err := doScanDir(0, path, pattern, isRecursive, func(path string) string {
|
|
if IsDir(path) {
|
|
return ""
|
|
}
|
|
return path
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(list) > 0 {
|
|
sort.Strings(list)
|
|
}
|
|
return list, nil
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// doScanDir is an internal method which scans directory and returns the absolute path
|
|
// list of files that are not sorted.
|
|
//
|
|
// 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 doScanDir(depth int, path string, pattern string, recursive bool, handler func(path string) string) ([]string, error) {
|
|
if depth >= maxScanDepth {
|
|
return nil, gerror.Newf("directory scanning exceeds max recursive depth: %d", maxScanDepth)
|
|
}
|
|
var (
|
|
list []string
|
|
file, err = Open(path)
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
names, err := file.Readdirnames(-1)
|
|
if err != nil {
|
|
err = gerror.Wrapf(err, `read directory files failed from path "%s"`, path)
|
|
return nil, err
|
|
}
|
|
var (
|
|
filePath = ""
|
|
patterns = gstr.SplitAndTrim(pattern, ",")
|
|
)
|
|
for _, name := range names {
|
|
filePath = path + Separator + name
|
|
if IsDir(filePath) && recursive {
|
|
array, _ := doScanDir(depth+1, filePath, pattern, true, handler)
|
|
if len(array) > 0 {
|
|
list = append(list, array...)
|
|
}
|
|
}
|
|
// Handler filtering.
|
|
if handler != nil {
|
|
filePath = handler(filePath)
|
|
if filePath == "" {
|
|
continue
|
|
}
|
|
}
|
|
// If it meets pattern, then add it to the result list.
|
|
for _, p := range patterns {
|
|
if match, _ := filepath.Match(p, name); match {
|
|
if filePath = Abs(filePath); filePath != "" {
|
|
list = append(list, filePath)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return list, nil
|
|
}
|