如何执行文件系统扫描

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

How to perform file system scanning

问题

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

我知道如何完成第二步(我将使用jstree在浏览器中显示它)。

英文:
  1. I need to write a function which when given the path of a folder
    scans the files rooted at that folder.
  2. And then I need to display the directory structure at that folder.

I know how to do 2 (I am going to use jstree to display it in the browser).

答案1

得分: 209

EDIT FOR 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)
}

EDIT: 足够多的人仍然点击这个答案,所以我想更新一下针对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

// 此代码不再起作用,请参见上面的内容
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)
}
英文:

EDIT FOR 1.16: Enough people still hit this answer, that I thought I'd update it for Go 1.16.

The function filepath.WalkDir introduced in Go 1.16 has better performance than filepath.Walk mentioned in the previous edit. Here's a working example:

package main

import (
	&quot;flag&quot;
	&quot;fmt&quot;
	&quot;io/fs&quot;
	&quot;path/filepath&quot;
)

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

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

EDIT: Enough people still hit this answer, that I thought I'd update it for the Go1 API. This is a working example of filepath.Walk(). The original is below.

package main

import (
  &quot;path/filepath&quot;
  &quot;os&quot;
  &quot;flag&quot;
  &quot;fmt&quot;
)

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


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

Please note that filepath.Walk walks the directory tree recursively.

This is an example run:

$ 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 &lt;nil&gt;

ORIGINAL ANSWER FOLLOWS: The interface for walking file paths has changed as of weekly.2011-09-16, see http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218. The code below will not work for release versions of GO in the near future.

There's actually a function in the standard lib just for this: filepath.Walk.

package main

import (
	&quot;path/filepath&quot;
	&quot;os&quot;
	&quot;flag&quot;
)

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

答案2

得分: 16

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

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")
		}
	}
}
英文:

Here's a way to obtain file information for the files in a directory.

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;path/filepath&quot;
)

func main() {
	dirname := &quot;.&quot; + 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(), &quot;bytes&quot;)
		}
	}
}

答案3

得分: 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)
	}
}
英文:

Here is an example to loop through all files and directories recursively. Note that if you want to know whether the path you're appending is a directory just check "f.IsDir()".

package main

import (
	&quot;fmt&quot;
	&quot;os&quot;
	&quot;path/filepath&quot;
)

func main() {
	searchDir := &quot;c:/path/to/dir&quot;
	
	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)
	}
}

答案4

得分: 7

github.com/kr/fs 包提供了一个具有非常有趣的 API 的 Walker

英文:

Package github.com/kr/fs provides a Walker with a very interesting API.

答案5

得分: 4

Go标准包ioutil中有内置函数来处理这种情况,如下所示的示例代码:

func searchFiles(dir string) { // dir是要搜索的父目录
    files, err := ioutil.ReadDir(dir)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        fmt.Println(file.Name())
    }
}
英文:

Go standard package ioutil has built in function for this case scenario see below example

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

得分: 1

请注意,“Walk不会遵循符号链接”,所以如果你想编写一个能够遵循符号链接的函数,我推荐使用ioutil.ReadDir。我的基准测试表明,它比filepath.Glob更快且占用的内存更少。

此外,ioutil.ReadDir使用基本字符串比较(strA > strB)对文件按基本名称进行排序。作为一个运维人员,我通常通过进行逆向数字比较(例如,最新构建排在前面)来对目录名称进行排序。如果你也是这种情况,那么最好直接调用os.ReadDirioutil.ReadDir在内部调用此方法),然后自己进行排序。

以下是使用数字排序的ReadDir部分的示例:

// ReadDirNumSort - 与ioutil/ReadDir相同,但返回一个按数字排序的文件列表。
//
// 参考自https://golang.org/src/io/ioutil/ioutil.go
// 版权所有2009年Go语言作者。版权所有。
// 使用此源代码受BSD风格的许可证管辖
// 可在LICENSE文件中找到。
//
// 修改了Sort方法,使用按数字排序的名称。
// 还允许逆向排序。
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实现了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
}
英文:

Note that "Walk does not follow symbolic links" so if you are looking to write a function that does that I recommend ioutil.ReadDir. My own benchmark test showed that it is faster and less memory intensive than filepath.Glob.

Additionally, ioutil.ReadDir is sorting files by basename using basic string comparison (strA &gt; strB). As a devops guy, I generally sort dir names by doing a reverse numerical comparison (latest build first for example). If that is also your case then it is better to call os.ReadDir directly (ioutil.ReadDir is calling this under the covers) and do the sorting yourself.

Here is an example of the ReadDir part with Numerical sort:

// 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() &lt; f[j].Name()
	}
	naj, err := strconv.Atoi(f[j].Name())
	if err != nil {
		return f[i].Name() &lt; f[j].Name()
	}
	return nai &lt; naj
}

答案7

得分: 0

你可能想在这里进行函数柯里化,以便能够充分利用搜索功能。

func visit(files *[]string) filepath.WalkFunc {
    return func (path string, info os.FileInfo, err error) error {
               // 可以在某个 if 块中执行此操作
               *files = append(*files, path)
               return nil
           }
}
英文:

You might want to do function currying here, so that you are able to fully utilise the search

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

答案8

得分: 0

func printAllFilesRecursively(input string) {
	filesInfo, _ := ioutil.ReadDir(input)
	for _, each := range filesInfo {
		println(input + "/" + each.Name())
		if each.IsDir() {
			printAllFilesRecursively(input + "/" + each.Name())
		}
	}
}
英文:
func printAllFilesRecursively(input string) {
	filesInfo, _ := ioutil.ReadDir(input)
	for _, each := range filesInfo {
		println(input + &quot;/&quot; + each.Name())
		if each.IsDir() {
			printAllFilesRecursively(input + &quot;/&quot; + each.Name())
		}
	}
}

huangapple
  • 本文由 发表于 2011年7月7日 18:05:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/6608873.html
匿名

发表评论

匿名网友

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

确定