GOLANG:遍历目录树并处理文件–错误=“没有这样的文件或目录”。

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

GOLANG: Walk Directory Tree and Process Files -- err = 'no such file or directory

问题

我正在编写一个遍历目录树并为找到的每个文件创建数字签名(加盐哈希)的例程。在测试时,我遇到了奇怪的行为 - 如果我给程序一个位于目录上方的根路径,程序可以遍历树并打印出文件名,但如果我尝试打开文件以读取其字节,则会收到“没有此文件或目录”的错误消息,而这个文件是例程找到的 - 不确定出了什么问题。Walk()例程如何“看到”文件,但ioutil.ReadFile()却找不到它?

示例代码:

// 从树的上层开始,比如$HOME
func doHashWalk(dirPath string) {
err := filepath.Walk(dirPath, walkFn)
// 在这里检查错误
}

func walkFn(path string, fi os.FileInfo, err error) (e error) {

if !fi.IsDir() {
    // 如果第一个字符是“。”,则跳过它,因为它是隐藏文件

    if strings.HasPrefix(fi.Name(), ".") {
        return nil
    }

    // 读取文件字节->获取绝对路径
    fullPath, err := filepath.Abs(path)
    if err != nil {
        log.Printf("Abs Err: %s", err)
    }

    // 这总是失败并显示错误
    bytes, err := ioutil.ReadFile(fullPath) // <-- (fi.Name()也不起作用)
    if err != nil {
        log.Printf("Err: %s, Bytes: %d", err, len(bytes))
    }

    // 创建加盐哈希
    ...
}
return nil

}

英文:

I'm writing a routine to walk a directory tree and create a digital signature (salted-hash) for each file I find. When testing it I get this weird behavior - if I give the program a root path "above" the directory, the program can walk the tree and print out the file names, but if I try and open the file to read it's bytes, I get the error message "no such file or directory" on the file that the routines found - not sure what gives here. How can the Walk() routine "see" the file, but ioutil.ReadFile() not be able to find it?

Sample Code:

// start with path higher up the tree, say $HOME
func doHashWalk(dirPath string) {
	err := filepath.Walk(dirPath, walkFn)
	// Check err here
}

func walkFn(path string, fi os.FileInfo, err error) (e error) {

	if !fi.IsDir() {
		// if the first character is a &quot;.&quot;, then skip it as it&#39;s a hidden file

		if strings.HasPrefix(fi.Name(), &quot;.&quot;) {
			return nil
		}

		// read in the file bytes -&gt; get the absolute path
		fullPath, err := filepath.Abs(fi.Name())
		if err != nil {
			log.Printf(&quot;Abs Err: %s&quot;, err)
		}

		// THIS ALWAYS FAILED WITH ERROR
		bytes, err := ioutil.ReadFile(fullPath) // &lt;-- (fi.Name() also doesn&#39;t work)
		if err != nil {
			log.Printf(&quot;Err: %s, Bytes: %d&quot;, err, len(bytes))     
		}

		// create the salted hash
		...
	}
	return nil
}

答案1

得分: 5

尝试在walkFn函数内部记录pathfullPath的值。

walkFn函数内部使用filepath.Abs()无法得到你想要的结果:它会将文件名解析为相对于当前工作目录的路径,而不是原始的dirPath

一种选择是在doHashWalk函数中提前将目标目录解析为绝对路径:

func doHashWalk(dirPath string) {
    fullPath, err := filepath.Abs(dirPath)

    if err != nil {
        log.Println("path error:", err)

        return
    }

    err = filepath.Walk(fullPath, walkFn)

    // 在这里检查错误
}

通过这个改变,walkFn回调函数将始终接收到一个完全合格的path参数;不需要再次调用filepath.Abs()

func walkFn(path string, fi os.FileInfo, err error) (e error) {
    // ...

    bytes, err := ioutil.ReadFile(path)

    // ...
}

如果对于你的应用程序来说,查看每个文件相对于原始的dirPath根目录的路径很重要,你可以通过闭包将该路径传递给walkFn回调函数:

func doHashWalk(dirPath string) error {

    fullPath, err := filepath.Abs(dirPath)

    if err != nil {
        return err
    }

    callback := func(path string, fi os.FileInfo, err error) error {
        return hashFile(fullPath, path, fi, err)
    }

    return filepath.Walk(fullPath, callback)
}

func hashFile(root string, path string, fi os.FileInfo, err error) error {
    if fi.IsDir() {
        return nil
    }

    rel, err := filepath.Rel(root, path)

    if err != nil {
        return err
    }

    log.Println("hash rel:", rel, "abs:", path)

    return nil
}

以上是翻译好的内容,请确认是否满意。

英文:

Try logging the values of path vs. fullPath inside of walkFn.

Using filepath.Abs() inside of walkFn does not give the result you want: it's resolving a filename relative to the current working directory, instead of the original dirPath.

One option is to resolve the target directory to an absolute path up-front in doHashWalk:

func doHashWalk(dirPath string) {
    fullPath, err := filepath.Abs(dirPath)

    if err != nil {
        log.Println(&quot;path error:&quot;, err)

        return
    }

    err = filepath.Walk(fullPath, walkFn)

    // check err here
}

With that change, the walkFn callback will always receive a fully-qualified path argument; no need to call filepath.Abs() again:

func walkFn(path string, fi os.FileInfo, err error) (e error) {
    // ...

    bytes, err := ioutil.ReadFile(path)

    // ...
}

If it's important for your application to see the path of each file relative to the original dirPath root, you can sneak that path into the walkFn callback via a closure:

func doHashWalk(dirPath string) error {

    fullPath, err := filepath.Abs(dirPath)

    if err != nil {
        return err
    }

    callback := func(path string, fi os.FileInfo, err error) error {
        return hashFile(fullPath, path, fi, err)
    }

    return filepath.Walk(fullPath, callback)
}

func hashFile(root string, path string, fi os.FileInfo, err error) error {
    if fi.IsDir() {
        return nil
    }

    rel, err := filepath.Rel(root, path)

    if err != nil {
        return err
    }

    log.Println(&quot;hash rel:&quot;, rel, &quot;abs:&quot;, path)

    return nil
}

答案2

得分: 0

问题在于你没有正确使用filepath.Walk函数。
你已经从path参数中获取了文件的路径。

文档可能并不是非常清楚,但它们确实对filepath.Walk函数有以下说明:

Walk函数遍历以root为根的文件树,对树中的每个文件或目录调用walkFn,包括root本身。

所以你可以将walkFn简化为以下形式:

func walkFn(path string, fi os.FileInfo, err error) (e error) {
    if !fi.IsDir() {
        bytes, err := ioutil.ReadFile(path) // path是文件的路径。
        if err != nil {
            fmt.Println("Fail")
        }
    }
    return nil
}

Walk函数会处理不通过..向上遍历文件树的情况,所以你不需要检查那个。至于绝对路径部分,我认为你也不需要,但我不能保证。

英文:

The problems is that you're not using the filepath.Walk exactly the way it's intended.
You allready get the path to the file from the path parameter.

The docs might not exactly be abundantly clear but they do say this for filepath.Walk:

> Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root.

So you could shorten walkFn to something like this:

func walkFn(path string, fi os.FileInfo, err error) (e error) {
    if !fi.IsDir() {
        bytes, err := ioutil.ReadFile(path) // path is the path to the file.
        if err != nil {
            fmt.Println(&quot;Fail&quot;)
        }
    }
    return nil
}

Walk will take care of not walking up the file-tree via .. there's no need for you to check for that. Considering the absolute path part I don't really think you need that either, but I make no promises GOLANG:遍历目录树并处理文件–错误=“没有这样的文件或目录”。

huangapple
  • 本文由 发表于 2013年12月5日 02:04:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/20382624.html
匿名

发表评论

匿名网友

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

确定