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配置參數設置為true來調用此庫以這樣做。
該庫的默認行為是在訪問每個節點之前始終對目錄的直接後代進行分類,就像filepath.Walk一樣。這通常是所需的行為。但是,當目錄節點有許多條目時,這確實會略有性能和內存懲罰。另外,如果呼叫者在配置參數中指定Unsorted枚舉,則讀取目錄會在呼叫者消耗條目時懶惰地執行。如果存在在訪問其節點之前不需要對目錄的直接後代進行排序的特定用例,則該庫將在設置為true Unsorted參數時跳過分類步驟。
這是關於以非確定順序遍歷文件系統層次結構的潛在讀物的有趣讀物。如果您知道要解決的問題不受訂單文件的影響,那麼我鼓勵您使用Unsorted 。否則跳過設置此選項。
研究人員發現Python腳本中的錯誤可能影響了數百項研究
該庫提供了上游代碼,並能夠在處理子女後指定每個目錄的回調函數。在以更有效的方式瀏覽文件系統後,這已用於遞歸刪除空目錄。有關此用法的示例,請參見examples/clean-empties目錄。
該庫提供了上游代碼,並能夠指定操作系統返回的錯誤的回調,從而允許上游代碼確定下一步的操作方案,是否停止行走層次結構,因為沒有提供錯誤回調,還是跳過導致錯誤的節點。有關此用法的示例,請參見examples/walk-fast目錄。