如何执行文件系统扫描


104
  1. 我需要编写一个函数,当给定文件夹的路径时,该函数会扫描以该文件夹为根的文件。
  2. 然后,我需要在该文件夹中显示目录结构。

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


2
您是否需要它递归遍历目录树?
newacct 2011年

Answers:


194

编辑:足够多的人仍然回答这个问题,我以为我会为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)
}

1
filepath.Walk不会顺便遵循符号链接。
0xcaff '16

3
@FrancescoPasa filepath.Walk回调将在符号链接(文件和目录)上触发。是的,它不会遵循它们,但是回调函数会识别符号链接并采取进一步的措施,即进行后续操作,以filepath.Walk确保首先未访问路径。
colm.anseo

15

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

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”的返回类型是什么,如何遍历它(它是地图吗?)..
sateayam 2013年

@heike:请参阅我的修改后的答案,该答案现在包括API文档。如您所见,Readdirmethod参数是n一个int。如果为n <= 0,则在单个片中Readdir返回FileInfo目录中的所有。
peterSO

@RickSmith:参见package os func (FileMode) IsRegular
peterSO

1
别挑剔,但是应该在错误检查之前推迟关闭。
Zanven '16

13

这是递归遍历所有文件和目录的示例。请注意,如果您想知道要追加的路径是否为目录,只需检查“ 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)args,而您需要使用err。除非在回答时是有效的?绝对是最新版本的编译错误。否则,非常有用,谢谢。
史蒂夫,


4

ioutil在这种情况下,Go标准软件包具有内置功能,请参见以下示例

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

1

请注意,“步行不跟随符号链接”,因此,如果您要编写一个建议这样做的函数,我建议使用ioutil.ReadDir。我自己的基准测试表明,它比filepath.Glob更快,内存占用更少。

此外,ioutil.ReadDir使用基本字符串比较(strA > strB)按基本名称对文件进行排序。作为一名开发人员,我通常通过进行反向数值比较(例如,首先构建最新版本)对目录名称进行排序。如果这也是您的情况,那么最好直接调用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
}

0

您可能希望在这里进行函数计算,以便能够充分利用搜索

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
           }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.