У меня есть два следующих способа поиска файлов с шаблоном имени (например, *.go
для поиска всех файлов go) по пути поиска (например, /Users/username/Desktop
). Первый метод использует recursion + goroutine, а второй метод использует очередь, чтобы предотвратить возможную проблему переполнения стека. Из моего тестирования на моем собственном компьютере Desktop
, в котором содержится 41 233 файла go, первый метод превосходит второй метод на 4 секунды, что составляет 18 и 22 секунды, соответственно.
Мне было интересно, есть ли лучший способ / параллелизм, чтобы сделать поиск еще более эффективным, потому что я интегрирую поиск в настольное приложение, и я не хочу, чтобы пользователь сидел там и ждал 30 секунд, прежде чем увидеть любые результаты поиска.
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
}