Source File
walk.go
Belonging Package
io/fs
// Copyright 2020 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.package fsimport ()// SkipDir is used as a return value from WalkDirFuncs to indicate that// the directory named in the call is to be skipped. It is not returned// as an error by any function.var SkipDir = errors.New("skip this directory")// WalkDirFunc is the type of the function called by WalkDir to visit// each file or directory.//// The path argument contains the argument to WalkDir as a prefix.// That is, if WalkDir is called with root argument "dir" and finds a file// named "a" in that directory, the walk function will be called with// argument "dir/a".//// The d argument is the fs.DirEntry for the named path.//// The error result returned by the function controls how WalkDir// continues. If the function returns the special value SkipDir, WalkDir// skips the current directory (path if d.IsDir() is true, otherwise// path's parent directory). Otherwise, if the function returns a non-nil// error, WalkDir stops entirely and returns that error.//// The err argument reports an error related to path, signaling that// WalkDir will not walk into that directory. The function can decide how// to handle that error; as described earlier, returning the error will// cause WalkDir to stop walking the entire tree.//// WalkDir calls the function with a non-nil err argument in two cases.//// First, if the initial fs.Stat on the root directory fails, WalkDir// calls the function with path set to root, d set to nil, and err set to// the error from fs.Stat.//// Second, if a directory's ReadDir method fails, WalkDir calls the// function with path set to the directory's path, d set to an// fs.DirEntry describing the directory, and err set to the error from// ReadDir. In this second case, the function is called twice with the// path of the directory: the first call is before the directory read is// attempted and has err set to nil, giving the function a chance to// return SkipDir and avoid the ReadDir entirely. The second call is// after a failed ReadDir and reports the error from ReadDir.// (If ReadDir succeeds, there is no second call.)//// The differences between WalkDirFunc compared to filepath.WalkFunc are://// - The second argument has type fs.DirEntry instead of fs.FileInfo.// - The function is called before reading a directory, to allow SkipDir// to bypass the directory read entirely.// - If a directory read fails, the function is called a second time// for that directory to report the error.//type WalkDirFunc func(path string, d DirEntry, err error) error// walkDir recursively descends path, calling walkDirFn.func ( FS, string, DirEntry, WalkDirFunc) error {if := (, , nil); != nil || !.IsDir() {if == SkipDir && .IsDir() {// Successfully skipped directory.= nil}return}, := ReadDir(, )if != nil {// Second call, to report ReadDir error.= (, , )if != nil {return}}for , := range {:= path.Join(, .Name())if := (, , , ); != nil {if == SkipDir {break}return}}return nil}// WalkDir walks the file tree rooted at root, calling fn for each file or// directory in the tree, including root.//// All errors that arise visiting files and directories are filtered by fn:// see the fs.WalkDirFunc documentation for details.//// The files are walked in lexical order, which makes the output deterministic// but requires WalkDir to read an entire directory into memory before proceeding// to walk that directory.//// WalkDir does not follow symbolic links found in directories,// but if root itself is a symbolic link, its target will be walked.func ( FS, string, WalkDirFunc) error {, := Stat(, )if != nil {= (, nil, )} else {= walkDir(, , &statDirEntry{}, )}if == SkipDir {return nil}return}type statDirEntry struct {info FileInfo}func ( *statDirEntry) () string { return .info.Name() }func ( *statDirEntry) () bool { return .info.IsDir() }func ( *statDirEntry) () FileMode { return .info.Mode().Type() }func ( *statDirEntry) () (FileInfo, error) { return .info, nil }