Go – Iterate through directores/files in current directory

huangapple go评论83阅读模式
英文:

Go - Iterate through directores/files in current directory

问题

我有以下的结构:

project/
    docs/
        index.html
    root.html

我想要遍历这个项目结构,以便读取每个文件的内容进行处理。所以我想说"在项目目录中搜索",然后它将搜索所有的文件,只搜索第一级目录及其文件,所以如果docs/下还有另一个目录和文件,它会忽略它。

目前,我尝试使用"path/filepath"库来实现这个:

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("这是一个目录!让我们遍历", file.Name())
                filepath.Walk(file.Name(), traverse)
            case mode.IsRegular():
                fmt.Println("这是一个文件", file.Name())
            }
        } else {
            return errors.New("无法检查状态")
        }
    }
    return errors.New("无法打开文件/目录")
}

然后我从这里调用它:

if err := filepath.Walk("project/", traverse); err != nil {
    setupErr("%s", err)
}

请注意,我相对于我的测试目录运行这个可执行文件,所以它可以找到目录。我的问题实际上是当我运行它时,我得到以下结果:

这是一个目录!让我们遍历 project
这是一个目录!让我们遍历 project
# ^ 这个打印了大约20次 ^
无法打开文件/目录

我认为我的递归有点问题,可能没有进入目录?有什么想法吗?如果你需要更多信息,请随时提问,我会更新。

英文:

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.

答案1

得分: 4

首先,看起来你想做的与你的代码相矛盾。你写道:

> 所以我想说“在项目目录中搜索”,然后它将搜索所有文件,只搜索第一级目录及其文件,所以如果在docs/下有另一个目录和文件,它将忽略它。

这是否意味着你只想迭代两级目录(当前目录和下一级目录),并忽略其他目录?

如果是这样,那么你不需要递归,只需要一个简单的循环,在当前目录中执行搜索函数,并对每个子目录执行相同的操作。

你现有的代码遍历了文件系统目录子树。

基本上,你使用的filepath.Walk应该可以实现这个功能。所以你要么实现递归遍历,要么使用Walk,但不能同时使用两者。

其次,你的代码中递归实现有错误。它没有遍历目录。

所以,打印当前目录及其子目录(但不再深入)中的文件名的代码是:

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() {
                    // 在这里处理文件
                    fmt.Println(item.Name() + "/" + subitem.Name())
                }
            }
        } else {
            // 在这里处理文件
            fmt.Println(item.Name())
        }
    }
}
英文:

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())
        }
    }
}

答案2

得分: 2

遍历以根目录为根的文件树,对树中的每个文件或目录(包括根目录)调用walkFn。walkFn会过滤访问文件和目录时出现的所有错误。文件按字典顺序遍历,这使得输出是确定性的,但对于非常大的目录,Walk可能效率低下。Walk不会跟随符号链接。

英文:

> 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.

huangapple
  • 本文由 发表于 2015年7月31日 00:28:37
  • 转载请务必保留本文链接:https://go.coder-hub.com/31729262.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定