godirwalk adalah perpustakaan untuk melintasi pohon direktori pada sistem file.
Singkatnya, mengapa saya membuat perpustakaan ini?
filepath.Walk .filepath.Walk .filepath.Walk .filepath.Walk .Bergantung pada keadaan spesifik Anda, Anda mungkin tidak lagi membutuhkan perpustakaan untuk file berjalan.
Contoh tambahan disediakan dalam examples/ subdirektori.
Perpustakaan ini akan menormalkan nama direktori tingkat atas yang disediakan berdasarkan pemisah jalur spesifik OS dengan memanggil filepath.Clean pada argumen pertamanya. Namun itu selalu memberikan pathname yang dibuat dengan menggunakan pemisah jalur spesifik OS yang benar saat memanggil fungsi panggilan balik yang disediakan.
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)
}) Perpustakaan ini tidak hanya menyediakan fungsi untuk melintasi pohon direktori sistem file, tetapi juga untuk mendapatkan daftar keturunan langsung dari direktori tertentu, biasanya jauh lebih cepat daripada menggunakan os.ReadDir atau os.ReadDirnames .
Inilah mengapa saya menggunakan godirwalk sebagai preferensi untuk filepath.Walk , os.ReadDir , dan os.ReadDirnames .
filepath.Walk Bila dibandingkan dengan filepath.Walk dalam tolok ukur, telah diamati berjalan antara lima dan sepuluh kali kecepatan di Darwin, dengan kecepatan yang sebanding dengan utilitas find Unix; dan sekitar dua kali kecepatan di Linux; dan sekitar empat kali kecepatan di windows.
Bagaimana cara mendapatkan peningkatan kinerja ini? Ini tidak lebih sedikit pekerjaan untuk memberi Anda output yang hampir sama. Perpustakaan ini menyebut fungsi syscall yang sama untuk melakukan pekerjaan, tetapi itu membuat lebih sedikit panggilan, tidak membuang informasi yang mungkin dibutuhkan, dan menciptakan lebih sedikit memori churn di sepanjang jalan dengan menggunakan kembali buffer goresan yang sama untuk membaca dari direktori daripada realokasi buffer baru setiap kali ia membaca file entri sistem file dari sistem operasi.
Saat melintasi pohon direktori sistem file, filepath.Walk memperoleh daftar keturunan langsung dari direktori, dan membuang informasi tipe simpul untuk entri sistem file yang disediakan oleh sistem operasi yang dilengkapi dengan nama node. Kemudian, segera sebelum memohon fungsi panggilan balik, filepath.Walk memanggil os.Stat untuk setiap node, dan meneruskan informasi os.FileInfo yang dikembalikan ke panggilan balik.
Sementara informasi os.FileInfo yang disediakan oleh os.Stat sangat membantu-dan bahkan menyertakan data os.FileMode -menyediakannya memerlukan panggilan sistem tambahan untuk setiap node.
Karena sebagian besar callback hanya peduli tentang apa tipe simpul, pustaka ini tidak membuang informasi tipe, tetapi memberikan informasi itu ke fungsi callback dalam bentuk nilai os.FileMode . Perhatikan bahwa nilai os.FileMode yang disediakan yang disediakan pustaka ini hanya memiliki informasi tipe simpul, dan tidak memiliki bit izin, bit lengket, atau informasi lain dari mode file. Jika panggilan balik tidak peduli dengan seluruh struktur data os.FileInfo node tertentu, panggilan balik dapat memohon os.Stat bila diperlukan, dan hanya bila diperlukan.
$ 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.WalkSaya sebelumnya juga tidak peduli tentang hal ini, tetapi humor saya. Kita semua menyukai bagaimana kita bisa menulis sekali dan berlari di mana -mana. Sangat penting untuk adopsi, pertumbuhan, dan kesuksesan bahasa, bahwa perangkat lunak yang kami buat dapat berjalan tanpa dimodifikasi pada semua arsitektur dan sistem operasi yang didukung oleh Go.
Ketika sistem file yang dilintasi memiliki lingkaran logis yang disebabkan oleh tautan simbolis ke direktori, pada unix filepath.Walk mengabaikan tautan simbolik dan melintasi seluruh pohon direktori tanpa kesalahan. Namun pada Windows, filepath.Walk akan terus mengikuti tautan simbolik direktori, meskipun tidak seharusnya, akhirnya menyebabkan filepath.Walk untuk mengakhiri lebih awal dan mengembalikan kesalahan ketika pathname menjadi terlalu lama dari menggabungkan loop tautan simbolik yang tak ada habisnya ke Pathname. Kesalahan ini berasal dari Windows, melewati filepath.Walk , dan ke klien hulu yang menjalankan filepath.Walk .
Takeaway adalah bahwa perilaku berbeda berdasarkan platform mana yang sedang filepath.Walk . Meskipun ini jelas tidak disengaja, sampai diperbaiki di perpustakaan standar, ia menghadirkan masalah kompatibilitas.
Perpustakaan ini memperbaiki masalah di atas sehingga tidak akan pernah mengikuti loop Sytem file logis pada Unix atau Windows. Selain itu, ia hanya akan mengikuti tautan simbolik ketika FollowSymbolicLinks yang diatur ke true. Perilaku pada Windows dan sistem operasi lainnya identik.
filepath.Walk Sementara perpustakaan ini berusaha untuk meniru perilaku filepath.Walk yang ditulis dengan sangat baik. Perpustakaan standar berjalan, ada tempat-tempat di mana ia sedikit menyimpang untuk menyediakan antarmuka penelepon yang lebih mudah atau intuitif.
Karena pustaka ini tidak memohon os.Stat pada setiap simpul sistem file yang ditemui, tidak ada kemungkinan peristiwa kesalahan untuk fungsi panggilan balik untuk difilter. Argumen ketiga dalam tanda fungsi filepath.WalkFunc untuk meneruskan kesalahan dari os.Stat ke fungsi callback tidak lagi diperlukan, dan dengan demikian dihilangkan dari tanda tangan fungsi callback dari perpustakaan ini.
Selain itu, sedikit perbedaan antarmuka antara filepath.WalkFunc dan WalkFunc perpustakaan ini menghilangkan kode boilerplate yang harus ditulis oleh penangan callback ketika mereka menggunakan filepath.Walk . Daripada setiap fungsi callback yang perlu memeriksa nilai kesalahan yang diteruskan ke dalamnya dan cabang sesuai, pengguna perpustakaan ini bahkan tidak memiliki nilai kesalahan untuk memeriksa segera setelah masuk ke fungsi callback. Ini adalah peningkatan baik dalam kinerja runtime dan kejelasan kode.
Pada setiap platform OS filepath.Walk memanggil fungsi panggilan balik dengan Pathname yang dibatasi solidus ( / ). Sebaliknya, perpustakaan ini memanggil panggilan balik dengan pemisah pathname khusus OS, meniadakan panggilan ke filepath.Clean dalam fungsi callback untuk setiap node sebelum benar-benar menggunakan pathname yang disediakan.
Dengan kata lain, bahkan di Windows, filepath.Walk akan memohon panggilan balik dengan some/path/to/foo.txt , yang membutuhkan klien yang ditulis dengan baik untuk melakukan normalisasi pathname untuk setiap file sebelum bekerja dengan file yang ditentukan. Ini adalah persyaratan boilerplate tersembunyi untuk membuat fungsi panggilan balik agnostik yang benar -benar OS. Sebenarnya, banyak klien yang dikembangkan di UNIX dan tidak diuji pada Windows mengabaikan kehalusan ini, dan akan menghasilkan bug perangkat lunak ketika seseorang mencoba menjalankan perangkat lunak itu di Windows.
Perpustakaan ini memanggil fungsi panggilan balik dengan somepathtofoo.txt untuk file yang sama saat berjalan di Windows, menghilangkan kebutuhan untuk menormalkan pathname oleh klien, dan mengurangi kemungkinan bahwa klien akan bekerja di UNIX tetapi tidak pada Windows.
Peningkatan ini menghilangkan kebutuhan untuk beberapa kode boilerplate yang lebih dalam fungsi callback sambil meningkatkan kinerja runtime dari perpustakaan ini.
godirwalk.SkipThis lebih intuitif untuk digunakan daripada filepath.SkipDir Salah satu aspek yang bisa dibilang membingungkan dari antarmuka filepath.WalkFunc yang harus ditiru oleh pustaka ini adalah bagaimana penelepon memberi tahu fungsi Walk untuk melewatkan entri sistem file. Dengan filepath.Walk dan Walk ini, ketika fungsi panggilan balik ingin melewatkan direktori dan tidak turun ke anak -anaknya, ia mengembalikan filepath.SkipDir . Jika fungsi callback mengembalikan filepath.SkipDir untuk non-direktori, filepath.Walk dan perpustakaan ini akan berhenti memproses entri lagi di direktori saat ini. Ini belum tentu seperti yang diinginkan atau diharapkan oleh sebagian besar pengembang. Jika Anda hanya ingin melewatkan entri non-direktori tertentu tetapi terus memproses entri di direktori, fungsi callback harus mengembalikan nol.
Implikasi dari desain antarmuka ini adalah ketika Anda ingin berjalan hierarki sistem file dan melewatkan entri, Anda harus mengembalikan nilai yang berbeda berdasarkan jenis entri sistem file apa node itu. Untuk melewatkan entri, jika entri adalah direktori, Anda harus mengembalikan filepath.SkipDir , dan jika entri bukan direktori, Anda harus mengembalikan nil . Ini adalah rintangan yang tidak menguntungkan yang telah saya amati banyak pengembang yang berjuang, hanya karena itu bukan antarmuka yang intuitif.
Berikut adalah contoh fungsi callback yang melekat pada antarmuka filepath.WalkFunc untuk melewatkannya entri sistem file apa pun yang pathname lengkapnya mencakup substring tertentu, optSkip . Perhatikan bahwa perpustakaan ini masih mendukung perilaku yang identik dari filepath.Walk ketika fungsi callback mengembalikan filepath.SkipDir .
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
} Perpustakaan ini berupaya menghilangkan beberapa boilerplate logika yang diperlukan dalam fungsi callback dengan memberikan nilai kesalahan token baru, SkipThis , yang dapat dikembalikan oleh fungsi panggilan balik untuk melewatkan entri sistem file saat ini terlepas dari jenis entri apa itu. Jika entri saat ini adalah direktori, anak -anaknya tidak akan disebutkan, persis seolah -olah panggilan balik telah mengembalikan filepath.SkipDir . Jika entri saat ini adalah non-direktori, entri sistem file berikutnya di direktori saat ini akan disebutkan, persis seolah-olah panggilan balik dikembalikan nil . Contoh fungsi panggilan balik berikut memiliki perilaku yang identik seperti sebelumnya, tetapi memiliki lebih sedikit boilerplate, dan memang logika yang saya temukan lebih sederhana untuk diikuti.
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 Perilaku default perpustakaan ini adalah mengabaikan tautan simbolis ke direktori saat berjalan di pohon direktori, seperti halnya filepath.Walk . Namun, itu memang meminta fungsi panggilan balik dengan setiap node yang ditemukannya, termasuk tautan simbolik. Jika ada kasus penggunaan tertentu untuk mengikuti tautan simbolik saat melintasi pohon direktori, perpustakaan ini dapat dipanggil dengan cara untuk melakukannya, dengan mengatur parameter konfigurasi Configlinks FollowSymbolicLinks ke true .
Perilaku default dari perpustakaan ini adalah untuk selalu mengurutkan keturunan langsung dari direktori sebelum mengunjungi setiap node, seperti halnya filepath.Walk . Ini biasanya perilaku yang diinginkan. Namun, ini memang datang dengan sedikit kinerja dan hukuman memori yang diperlukan untuk mengurutkan nama ketika simpul direktori memiliki banyak entri. Selain itu jika penelepon menentukan pencacahan Unsorted dalam parameter konfigurasi, Direktori Membaca dilakukan dengan malas saat penelepon mengkonsumsi entri. Jika ada kasus penggunaan tertentu yang tidak memerlukan penyortiran keturunan langsung direktori sebelum mengunjungi nodenya, perpustakaan ini akan melewatkan langkah penyortiran ketika parameter Unsorted diatur ke true .
Berikut adalah bacaan yang menarik tentang potensi hazzard untuk melintasi hierarki sistem file dalam urutan non-deterministik. Jika Anda tahu masalah yang Anda selesaikan tidak terpengaruh oleh file pesanan dikunjungi, maka saya mendorong Anda untuk menggunakan Unsorted . Jika tidak, lewati pengaturan opsi ini.
Peneliti menemukan bug dalam skrip Python mungkin telah mempengaruhi ratusan studi
Perpustakaan ini memberikan kode hulu dengan kemampuan untuk menentukan fungsi panggilan balik yang akan dipanggil untuk setiap direktori setelah anak -anaknya diproses. Ini telah digunakan untuk menghapus direktori kosong secara rekursif setelah melintasi sistem file dengan cara yang lebih efisien. Lihat examples/clean-empties untuk contoh penggunaan ini.
Perpustakaan ini memberikan kode hulu dengan kemampuan untuk menentukan panggilan balik yang akan dipanggil untuk kesalahan bahwa sistem operasi kembali, memungkinkan kode hulu untuk menentukan tindakan berikutnya untuk diambil, apakah akan berhenti berjalan hierarki, karena tidak ada kesalahan callback yang disediakan, atau melewatkan node yang menyebabkan kesalahan. Lihat examples/walk-fast untuk contoh penggunaan ini.