【问题标题】:How to perform file system scanning如何执行文件系统扫描
【发布时间】:2011-09-30 08:01:00
【问题描述】:
  1. 我需要编写一个函数,当给定文件夹的路径时 扫描以该文件夹为根的文件。
  2. 然后我需要显示该文件夹中的目录结构。

我知道怎么做2(我将使用jstree在浏览器中显示它)。

【问题讨论】:

  • 是否需要递归遍历目录树?

标签: file go directory


【解决方案1】:

为 1.16 编辑:仍然有足够多的人点击这个答案,我想我会为 Go 1.16 更新它。

Go 1.16 中引入的函数filepath.WalkDir 比之前编辑中提到的filepath.Walk 具有更好的性能。这是一个工作示例:

package main

import (
    "flag"
    "fmt"
    "io/fs"
    "path/filepath"
)

func visit(path string, di fs.DirEntry, err error) error {
    fmt.Printf("Visited: %s\n", path)
    return nil
}

func main() {
    flag.Parse()
    root := flag.Arg(0)
    err := filepath.WalkDir(root, visit)
    fmt.Printf("filepath.WalkDir() returned %v\n", err)
}

编辑:仍然有足够多的人点击这个答案,我想我会为 Go1 API 更新它。这是filepath.Walk() 的一个工作示例。原文如下。

package main

import (
  "path/filepath"
  "os"
  "flag"
  "fmt"
)

func visit(path string, f os.FileInfo, err error) error {
  fmt.Printf("Visited: %s\n", path)
  return nil
} 


func main() {
  flag.Parse()
  root := flag.Arg(0)
  err := filepath.Walk(root, visit)
  fmt.Printf("filepath.Walk() returned %v\n", err)
}

请注意 filepath.Walk 递归遍历目录树。

这是一个运行示例:

$ mkdir -p dir1/dir2
$ touch dir1/file1 dir1/dir2/file2
$ go run walk.go dir1
Visited: dir1
Visited: dir1/dir2
Visited: dir1/dir2/file2
Visited: dir1/file1
filepath.Walk() returned <nil>

原始答案如下: 自 2011 年 9 月 16 日起,遍历文件路径的界面已更改,请参阅 http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218。下面的代码在不久的将来将不适用于 GO 的发布版本。

标准库中实际上有一个函数用于此目的:filepath.Walk

package main

import (
    "path/filepath"
    "os"
    "flag"
)

type visitor int

// THIS CODE NO LONGER WORKS, PLEASE SEE ABOVE
func (v visitor) VisitDir(path string, f *os.FileInfo) bool {
    println(path)
    return true
} 

func (v visitor) VisitFile(path string, f *os.FileInfo) {
    println(path)
}

func main() {
    root := flag.Arg(0)
    filepath.Walk(root, visitor(0), nil)
}

【讨论】:

  • filepath.Walk 顺便说一下不遵循符号链接。
  • @FrancescoPasa filepath.Walk 回调将在符号链接(文件和目录)上触发。是的,它不会跟随它们,但回调会识别符号链接并采取进一步的行动,即跟进filepath.Walk,首先确保该路径尚未被访问。
【解决方案2】:

这是一种获取目录中文件的文件信息的方法。

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    dirname := "." + string(filepath.Separator)
    d, err := os.Open(dirname)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    defer d.Close()
    fi, err := d.Readdir(-1)
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    for _, fi := range fi {
        if fi.Mode().IsRegular() {
            fmt.Println(fi.Name(), fi.Size(), "bytes")
        }
    }
}

【讨论】:

  • @peterSO : Readdir(-1) 是什么意思?由于Readdir只接受字符串类型,并且根据API文档,字符串不能为NUL,没有其他限制.. Readdir中“fi”的返回类型是什么,怎么可以遍历(是地图吗?)..
  • @heike:查看我修改后的答案,现在包括 API 文档。如您所见,Readdir 方法参数是nint。如果n &lt;= 0Readdir 在一个切片中返回目录中的所有FileInfo
  • @RickSmith:见包裹osfunc (FileMode) IsRegular
  • 不要挑剔,但您的延迟关闭应该发生在错误检查之前。
【解决方案3】:

这是一个递归遍历所有文件和目录的示例。请注意,如果您想知道要附加的路径是否为目录,只需检查“f.IsDir()”即可。

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    searchDir := "c:/path/to/dir"

    fileList := []string{}
    err := filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
        fileList = append(fileList, path)
        return nil
    })

    for _, file := range fileList {
        fmt.Println(file)
    }
}

【讨论】:

  • 你复制粘贴函数了吗? main 方法不应该有 ([]string, error) 参数,你需要对 err 做一些事情。除非在回答时它是有效的?在更新的版本中绝对是一个编译错误。否则,非常有用,谢谢。
【解决方案4】:

github.com/kr/fsWalker 提供了一个非常有趣的API。

【讨论】:

    【解决方案5】:

    Go 标准包ioutil 已内置此案例场景的功能,请参见下面的示例

    func searchFiles(dir string) { // dir is the parent directory you what to search
        files, err := ioutil.ReadDir(dir)
        if err != nil {
            log.Fatal(err)
        }
    
        for _, file := range files {
            fmt.Println(file.Name())
        }
    }
    

    【讨论】:

      【解决方案6】:

      请注意“Walk 不遵循符号链接”,因此如果您正在寻找执行此操作的函数,我推荐 ioutil.ReadDir。我自己的基准测试表明,它比filepath.Glob 更快且内存占用更少。

      此外,ioutil.ReadDir 正在使用基本字符串比较 (strA &gt; strB) 按基本名称对文件进行排序。作为一个 devops 人,我通常通过进行反向数字比较来对目录名称进行排序(例如,首先构建最新版本)。如果这也是你的情况,那么最好直接调用os.ReadDirioutil.ReadDir 在幕后调用它)并自己进行排序。

      这是一个使用数字排序的ReadDir 部分示例:

      // ReadDirNumSort - Same as ioutil/ReadDir but uses returns a Numerically
      // Sorted file list.
      //
      // Taken from https://golang.org/src/io/ioutil/ioutil.go
      // Copyright 2009 The Go Authors. All rights reserved.
      // Use of this source code is governed by a BSD-style
      // license that can be found in the LICENSE file.
      //
      // Modified Sort method to use Numerically sorted names instead.
      // It also allows reverse sorting.
      func ReadDirNumSort(dirname string, reverse bool) ([]os.FileInfo, error) {
          f, err := os.Open(dirname)
          if err != nil {
              return nil, err
          }
          list, err := f.Readdir(-1)
          f.Close()
          if err != nil {
              return nil, err
          }
          if reverse {
              sort.Sort(sort.Reverse(byName(list)))
          } else {
              sort.Sort(byName(list))
          }
          return list, nil
      }
      
      // byName implements sort.Interface.
      type byName []os.FileInfo
      
      func (f byName) Len() int      { return len(f) }
      func (f byName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
      func (f byName) Less(i, j int) bool {
          nai, err := strconv.Atoi(f[i].Name())
          if err != nil {
              return f[i].Name() < f[j].Name()
          }
          naj, err := strconv.Atoi(f[j].Name())
          if err != nil {
              return f[i].Name() < f[j].Name()
          }
          return nai < naj
      }
      

      【讨论】:

        【解决方案7】:

        您可能想在此处进行函数柯里化,以便您能够充分利用搜索

        func visit(files *[]string) filepath.WalkFunc {
            return func (path string, info os.FileInfo, err error) error {
                       // maybe do this in some if block
                       *files = append(*files, path)
                       return nil
                   }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-26
          • 2011-05-08
          • 1970-01-01
          相关资源
          最近更新 更多