godirwalk是一个库,用于遍历文件系统上的目录树。
简而言之,为什么我要创建这个库?
filepath.Walk快。filepath.Walk更正确。filepath.Walk更容易使用。filepath.Walk更灵活。根据您的特定情况,您可能不再需要图书馆才能在Go中走。
examples/子目录中提供了其他示例。
该库将通过在其第一个参数上调用filepath.Clean 。但是,在调用提供的回调函数时,它始终提供通过使用正确的OS特定路径分离器创建的路径名。
dirname := "some/directory/root"
err := godirwalk . Walk ( dirname , & godirwalk. Options {
Callback : func ( osPathname string , de * godirwalk. Dirent ) error {
// Following string operation is not most performant way
// of doing this, but common enough to warrant a simple
// example here:
if strings . Contains ( osPathname , ".git" ) {
return godirwalk . SkipThis
}
fmt . Printf ( "%s %s n " , de . ModeType (), osPathname )
return nil
},
Unsorted : true , // (optional) set true for faster yet non-deterministic enumeration (see godoc)
})该库不仅提供了遍历文件系统目录树的功能,而且还提供了获得特定目录的直接后代列表的列表,通常比使用os.ReadDir或os.ReadDirnames要快得多。
这就是为什么我godirwalk filepath.Walk , os.ReadDir和os.ReadDirnames的原因。
filepath.Walk更快与filepath.Walk相比,在基准中进行了扫描时,已经观察到它的运行速度是达尔文的五倍至十倍,其速度与Unix find实用程序的速度相当;大约是Linux上的两倍;大约是窗户上的速度的四倍。
它如何获得这种性能的提升?为您提供几乎相同的输出,它做的工作较少。该库调用相同的syscall功能来完成这项工作,但是它会更少的呼叫,不会丢弃可能需要的信息,并通过重复使用相同的刮擦缓冲区来从目录中读取而不是每次从操作系统读取文件系统输入数据的新缓冲区,从而使内存流失较少。
在遍历文件系统目录树时, filepath.Walk获取目录的直接后代列表,并扔掉由节点名称随附的操作系统提供的文件系统条目的节点类型信息。然后,在调用回调函数之前,立即filepath.Walk调用每个节点的os.Stat ,然后将返回的os.FileInfo信息传递到回调。
虽然os.Stat提供的os.FileInfo信息非常有用(甚至包括os.FileMode数据),因此它需要为每个节点提供一个额外的系统调用。
因为大多数回调仅关心节点类型是什么,所以此库不会将类型的信息丢弃,而是以os.FileMode值的形式将该信息提供给回调函数。请注意,该库提供的提供的os.FileMode值仅具有节点类型信息,并且没有文件模式中的权限位,粘性位或其他信息。如果回调确实在乎特定节点的整个os.FileInfo数据结构,则该回调可以在需要时添加调用os.Stat ,并且仅在需要时才插入。
$ go test -bench=. -benchmem
goos: darwin
goarch: amd64
pkg: github.com/karrick/godirwalk
BenchmarkReadDirnamesStandardLibrary-12 50000 26250 ns/op 10360 B/op 16 allocs/op
BenchmarkReadDirnamesThisLibrary-12 50000 24372 ns/op 5064 B/op 20 allocs/op
BenchmarkFilepathWalk-12 1 1099524875 ns/op 228415912 B/op 416952 allocs/op
BenchmarkGodirwalk-12 2 526754589 ns/op 103110464 B/op 451442 allocs/op
BenchmarkGodirwalkUnsorted-12 3 509219296 ns/op 100751400 B/op 378800 allocs/op
BenchmarkFlameGraphFilepathWalk-12 1 7478618820 ns/op 2284138176 B/op 4169453 allocs/op
BenchmarkFlameGraphGodirwalk-12 1 4977264058 ns/op 1031105328 B/op 4514423 allocs/op
PASS
ok github.com/karrick/godirwalk 21.219s$ go test -bench=. -benchmem
goos: linux
goarch: amd64
pkg: github.com/karrick/godirwalk
BenchmarkReadDirnamesStandardLibrary-12 100000 15458 ns/op 10360 B/op 16 allocs/op
BenchmarkReadDirnamesThisLibrary-12 100000 14646 ns/op 5064 B/op 20 allocs/op
BenchmarkFilepathWalk-12 2 631034745 ns/op 228210216 B/op 416939 allocs/op
BenchmarkGodirwalk-12 3 358714883 ns/op 102988664 B/op 451437 allocs/op
BenchmarkGodirwalkUnsorted-12 3 355363915 ns/op 100629234 B/op 378796 allocs/op
BenchmarkFlameGraphFilepathWalk-12 1 6086913991 ns/op 2282104720 B/op 4169417 allocs/op
BenchmarkFlameGraphGodirwalk-12 1 3456398824 ns/op 1029886400 B/op 4514373 allocs/op
PASS
ok github.com/karrick/godirwalk 19.179sfilepath.Walk更正确我以前也不在乎这个,但让我幽默。我们都喜欢如何写作一次并在任何地方奔跑。对于语言的采用,增长和成功,我们创建的软件可以在GO支持的所有架构和操作系统上运行。
当遍历的文件系统具有符合目录的符号链接引起的逻辑循环时,walk忽略了符号链接,并在没有错误的情况下遍历整个filepath.Walk树。但是,在Windows上, filepath.Walk将继续按照目录符号链接继续,即使不应该这样做,最终会导致filepath.Walk时,当PathName从串联符号链接的无尽循环中汇总到PathName时,PATHNAME变得太长时返回错误。此错误来自Windows,通过filepath.Walk以及运行filepath.Walk的上游客户端。
要点是,基于platform filepath.Walk正在运行的行为不同。尽管这显然不是故意的,但是直到将其固定在标准库中,它就提出了兼容性问题。
该库解决了上述问题,因此它永远不会遵循UNIX或Windows上的逻辑文件系统循环。此外,只有在FollowSymbolicLinks设置为true时,它将仅遵循符号链接。 Windows和其他操作系统上的行为是相同的。
filepath.Walk更容易使用。虽然该库努力模仿写得很好的filepath.Walk的行为。步行标准库,但在某些地方,它会有所偏离,以便提供更简单或直观的呼叫者界面。
由于此库未调用os.Stat在每个文件系统节点上都遇到的os遇到,因此回调函数没有可能过滤的错误事件。 filepath.WalkFunc函数签名中的第三个参数将不再需要从os.Stat传递到回调函数,因此不再需要从此库的回调函数签名中删除。
此外, filepath.WalkFunc和该库的WalkFunc之间的这种轻微的接口差消除了回调处理程序在使用filepath.Walk时必须写入的样板代码。与其需要检查传递到该错误值并相应分支的每个回调函数,该库的用户甚至没有错误值即可在输入回调函数时立即检查。这是运行时性能和代码清晰度的改进。
在每个OS平台filepath.Walk上。步行以Solidus( / )定界路径名调用回调函数。相比之下,此库将使用特定于OS的路径名分隔符调用回调,从而在实际使用提供的PathName之前,在每个节点的回调函数中删除了对filepath.Clean的调用。
换句话说,即使在Windows上, filepath.Walk也会使用some/path/to/foo.txt回调,要求写入良好的客户在使用指定文件之前对每个文件执行pathName归一化。这是一个隐藏的样板要求,以创建真正的OS不可知论回调功能。实际上,许多客户端在UNIX上开发而不是在Windows上进行测试,而忽略了此微妙的,并且当某人试图在Windows上运行该软件时会导致软件错误。
该库在Windows上运行时使用somepathtofoo.txt调用回调函数,从而消除了客户端将路径名归一化的需求,并减少了客户端在UNIX上工作但在Windows上工作的可能性。
这种增强功能消除了回调功能中一些更多样板代码的必要性,同时改善了此库的运行时性能。
godirwalk.SkipThis比filepath.SkipDir更直观可以说, filepath.WalkFunc的一个方面一个令人困惑的方面。该库必须效仿的WalkFunc接口是呼叫者告诉Walk功能以跳过文件系统条目。随着filepath.Walk和该图书馆的Walk ,回调功能想要跳过目录而不是下降到孩子时,它返回了filepath.SkipDir 。如果回调函数返回非直接式filepath.SkipDir ,则filepath.Walk和该库将停止处理当前目录中的任何其他条目。这不一定是大多数开发人员想要或期望的。如果您想简单地跳过特定的非直接输入条目,但请继续在目录中处理条目,则回调函数必须返回nil。
此接口设计的含义是当您想走一个文件系统层次结构并跳过条目时,您必须根据节点是哪种类型的文件系统条目返回其他值。要跳过条目,如果条目是目录,则必须返回filepath.SkipDir ,如果条目不是目录,则必须返回nil 。这是我观察到许多开发人员挣扎的不幸障碍,仅仅是因为它不是直观的界面。
这是一个示例回调函数,该函数遵循filepath.WalkFunc接口,以使其跳过任何文件系统条目,其完整路径名包括特定的子字符串optSkip 。请注意,当回调函数返回filepath.SkipDir时,该库仍然支持filepath.Walk的相同行为。
func callback1 ( osPathname string , de * godirwalk. Dirent ) error {
if optSkip != "" && strings . Contains ( osPathname , optSkip ) {
if b , err := de . IsDirOrSymlinkToDir (); b == true && err == nil {
return filepath . SkipDir
}
return nil
}
// Process file like normal...
return nil
}该库试图通过提供新的令牌错误值SkipThis来消除回调功能中所需的一些逻辑样板,而该库可返回回调函数,无论其是什么类型的输入,都可以返回以跳过当前的文件系统条目。如果当前条目是目录,则不会列举其子女,就像回调返回filepath.SkipDir一样。如果当前条目是非直接导向,则将列举当前目录中的下一个文件系统条目,就像回调返回的nil 。下面的示例回调函数具有与以前相同的行为,但具有较少的样板,并且公认我发现更易于遵循的逻辑。
func callback2 ( osPathname string , de * godirwalk. Dirent ) error {
if optSkip != "" && strings . Contains ( osPathname , optSkip ) {
return godirwalk . SkipThis
}
// Process file like normal...
return nil
}filepath.Walk更灵活。 该库的默认行为是忽略在漫步目录树时忽略与目录的符号链接,就像filepath.Walk一样。但是,它确实可以使用它找到的每个节点调用回调函数,包括符号链接。如果存在特定的用例在遍历目录树时遵循符号链接,则可以通过将FollowSymbolicLinks config参数设置为true来调用此库以这样做。
该库的默认行为是在访问每个节点之前始终对目录的直接后代进行分类,就像filepath.Walk一样。这通常是所需的行为。但是,当目录节点有许多条目时,这确实会略有性能和内存惩罚。另外,如果呼叫者在配置参数中指定Unsorted枚举,则读取目录会在呼叫者消耗条目时懒惰地执行。如果存在在访问其节点之前不需要对目录的直接后代进行排序的特定用例,则该库将在设置为true Unsorted参数时跳过分类步骤。
这是关于以非确定顺序遍历文件系统层次结构的潜在读物的有趣读物。如果您知道要解决的问题不受订单文件的影响,那么我鼓励您使用Unsorted 。否则跳过设置此选项。
研究人员发现Python脚本中的错误可能影响了数百项研究
该库提供了上游代码,并能够在处理子女后指定每个目录的回调函数。在以更有效的方式浏览文件系统后,这已用于递归删除空目录。有关此用法的示例,请参见examples/clean-empties目录。
该库提供了上游代码,并能够指定操作系统返回的错误的回调,从而允许上游代码确定下一步的操作方案,是否停止行走层次结构,因为没有提供错误回调,还是跳过导致错误的节点。有关此用法的示例,请参见examples/walk-fast目录。