Reputation: 929
I have the following structure:
project/
docs/
index.html
root.html
I'm trying to iterate through this project structure so that I can read the contents of each file to process them. So I want to say "search through the directory project", then it will search through all the files, and only the first level of directories and their files, so if there was another directory with a file inside of docs/
, it would ignore it.
Currently, I've tried to accomplish this with the "path/filepath" library:
func traverse(path string, file os.FileInfo, err error) error {
if file, err := os.Open(file.Name()); err == nil {
defer file.Close()
if fileStat, err := file.Stat(); err == nil {
switch mode := fileStat.Mode(); {
case mode.IsDir():
fmt.Println("it be a directory! lets traverse", file.Name())
filepath.Walk(file.Name(), traverse)
case mode.IsRegular():
fmt.Println("the thingy ", file.Name(), " is a file")
}
} else {
return errors.New("failed to check status")
}
}
return errors.New("failed 2 open file/dir?")
}
Then I call it from here:
if err := filepath.Walk("project/", traverse); err != nil {
setupErr("%s", err)
}
Note that I run this executable relative to my test directory, so it's finding the directory okay. My problem is actually when I run it, I get the following:
it be a directory! lets traverse project
it be a directory! lets traverse project
# ^ printed about 20 more times ^
failed 2 open file/dir?
I think my recursion is a little off, and it's not changing into the directory perhaps? Any ideas, if you need any more information just ask and I'll update.
Upvotes: 2
Views: 29629
Reputation: 13532
First, it looks like what you want do to contradicts with the code you have. You wrote:
So I want to say "search through the directory project", then it will search through all the files, and only the first level of directories and their files, so if there was another directory with a file inside of docs/, it would ignore it.
Does it mean that you want to iterate only two levels of directories (current and one below) and ignore the rest?
If so then you do not need a recursion, just a simple loop that executes search function over the files within the current directory and for every its subdirectory.
The code that you have walks over the filesystem directory subtree.
Basically, filepath.Walk
that you use should do it for you. So you either implement recursive walking or use Walk, but not both.
Second, the recursion is implemented incorrectly in your code. It missing iterating over the directories.
So the code that prints the file names in the current directory and its subdirectories (but not further) is:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
items, _ := ioutil.ReadDir(".")
for _, item := range items {
if item.IsDir() {
subitems, _ := ioutil.ReadDir(item.Name())
for _, subitem := range subitems {
if !subitem.IsDir() {
// handle file there
fmt.Println(item.Name() + "/" + subitem.Name())
}
}
} else {
// handle file there
fmt.Println(item.Name())
}
}
}
Upvotes: 7
Reputation: 2129
Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root. All errors that arise visiting files and directories are filtered by walkFn. The files are walked in lexical order, which makes the output deterministic but means that for very large directories Walk can be inefficient. Walk does not follow symbolic links.
Upvotes: 2