遍歷資料夾是一個我們經常遇到的操作,檔案系統是一個樹形結構,我經常喜歡拿這個作為練手例子,比方可以拿來考查遞迴,這個例子是一個遍歷資料夾獲取檔案的函式,沒有使用遞迴,只有20行左右的程式碼。
思路就是用兩個slice來儲存所需的資料,其中一個路徑slice以棧的形式來儲存需遍歷的資料夾,出棧入棧迴圈遍歷資料夾以及子資料夾:
func scanAll(path string) []string {
var result []string //結果集
paths := []string{path} //目錄棧:儲存需要遍歷的資料夾,初始化時傳入需要遍歷的資料夾
for len(paths) > 0 { //目錄棧不為空則不斷迴圈
//出棧pop
dir := paths[len(paths)-1]
paths = paths[:len(paths)-1]
//遍歷pop出的的資料夾
files, _ := ioutil.ReadDir(dir)
for _, f := range files {
p := dir + "/" + f.Name() //拼接路徑
if f.IsDir() {
paths = append(paths, p) //如果是資料夾型別則入棧
} else {
result = append(result, p) //如果是檔案則存結果
}
}
}
return result
}
改成遞迴的話可以這麼寫:
func scanAllByRecursive(path string) []string {
var result, tmp []string //結果集
files, _ := ioutil.ReadDir(path)
for _, f := range files {
p := path + "/" + f.Name()
if f.IsDir() {
tmp = scanAllByRecursive(p)
} else {
result = append(result, p)
}
}
return append(result, tmp...)
}
還可以這麼寫,把儲存容器放在外部,作為接收器:
type Stack []string
var result Stack
result.scanAllByRecursive(".")
func (result *Stack) scanAllByRecursive(path string) {
files, _ := ioutil.ReadDir(path)
for _, f := range files {
p := path + "/" + f.Name()
if f.IsDir() {
result.scanAllByRecursive(p)
} else {
*result = append(*result, p)
}
}
}