I have the two following methods for searching for files with a name pattern (e.g. *.go
for finding all go files) under a search path (e.g. /Users/username/Desktop
). The first method uses recursion + goroutine, and the second method uses a queue to prevent possible stack overflow problem. From my testing on my own computer Desktop
that has 41,233 go files, the first method beats the second method by 4 seconds, which are 18 and 22 seconds, respectively.
I was wondering if there is any better way/parallelism to make the search even more efficient, because I am integrating the search in a desktop app, and I don't want the user sitting there and wait for 30 seconds before seeing any search results.
type FileSearcher struct {
Contents []MyFile
}
func (fe *FileSearcher) FindFileRecursive(searchPath, namePattern string) (err error) {
// get absolute path
if searchPath, err = filepath.Abs(searchPath); err != nil {
return
}
curFileName := filepath.Base(searchPath)
if matched, err := filepath.Match(namePattern, curFileName); err == nil && matched {
if foundFile, err := NewFileFromPath(searchPath); err == nil {
fe.Contents = append(fe.Contents, *foundFile) // found a match
}
} else {
return
}
if isDir, _ := utils.IsDirectory(searchPath); isDir {
if files, err := ioutil.ReadDir(searchPath); err == nil {
for _, f := range files {
fPath := filepath.Join(searchPath, f.Name())
go fe.FindFileRecursive(fPath, namePattern) // recursive in a goroutine here
}
}
}
return
}
// FindFile searches for files/directories matching namePattern under searchPath
func (fe *FileSearcher) FindFile(searchPath, namePattern string) (err error) {
queue := make([]string, 0)
queue = append(queue, searchPath)
for len(queue) > 0 {
path := queue[0]
curFileName := filepath.Base(path) // get the file/directory name at this path
queue = queue[1:] // pop off the head
if matched, err := filepath.Match(namePattern, curFileName); err == nil && matched {
if foundFile, err := NewFileFromPath(path); err == nil {
fe.Contents = append(fe.Contents, *foundFile) // found a match
}
}
if isDir, _ := utils.IsDirectory(path); isDir {
if files, err := ioutil.ReadDir(path); err == nil {
for _, f := range files {
fPath := filepath.Join(path, f.Name())
queue = append(queue, fPath) // push the new dir path to queue
}
}
}
}
return
}