我正在编写一个例程来遍历目录树,并为我找到的每个文件创建一个数字签名(salted-hash)。在测试它时,我得到了这种奇怪的行为 - 如果我给程序一个根目录“在”目录之上,程序可以遍历树并打印出文件名,但是如果我尝试打开文件来读取它的字节,我在例程找到的文件上得到错误消息“没有这样的文件或目录” - 不知道这里给出了什么。 Walk()例程如何“查看”该文件,但是ioutil.ReadFile()无法找到它?
示例代码:
// 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 ".", then skip it as it's a hidden file
if strings.HasPrefix(fi.Name(), ".") {
return nil
}
// read in the file bytes -> get the absolute path
fullPath, err := filepath.Abs(fi.Name())
if err != nil {
log.Printf("Abs Err: %s", err)
}
// THIS ALWAYS FAILED WITH ERROR
bytes, err := ioutil.ReadFile(fullPath) // <-- (fi.Name() also doesn't work)
if err != nil {
log.Printf("Err: %s, Bytes: %d", err, len(bytes))
}
// create the salted hash
...
}
return nil
}
答案 0 :(得分:4)
尝试在path
内记录fullPath
与walkFn
的值。
在filepath.Abs()
内使用walkFn
并不能提供您想要的结果:它正在解析相对于当前工作目录的文件名,而不是原始的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)
// check err here
}
通过该更改,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
}
答案 1 :(得分:0)
问题是你没有按照预期的方式使用filepath.Walk
。
您已经从path
参数获取了该文件的路径。
docs可能并不十分清楚,但他们确实对filepath说了这么做.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 is the path to the file.
if err != nil {
fmt.Println("Fail")
}
}
return nil
}
步行将负责不通过..
走向文件树,您无需检查。考虑到绝对路径部分我不认为你也需要它,但我没有做出任何承诺;)