godirwalk هي مكتبة لاجتياز شجرة الدليل على نظام الملفات.
باختصار ، لماذا قمت بإنشاء هذه المكتبة؟
filepath.Walk .filepath.Walk .filepath.Walk .filepath.Walk .اعتمادًا على ظروفك المحددة ، قد لا تحتاج إلى مكتبة للملف المشي في GO.
يتم توفير أمثلة إضافية في examples/ الدليل الفرعي.
ستقوم هذه المكتبة بتطبيع اسم دليل المستوى الأعلى المقدم استنادًا إلى فاصل المسار الخاص بنظام التشغيل عن طريق استدعاء filepath.Clean على حجتها الأولى. ومع ذلك ، فإنه يوفر دائمًا اسم المسار الذي تم إنشاؤه باستخدام فاصل المسار الصحيح الخاص بنظام التشغيل عند التذرع بوظيفة رد الاتصال المقدمة.
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 Fettility ؛ وحوالي ضعف السرعة على Linux ؛ وحوالي أربعة أضعاف السرعة على النوافذ.
كيف تحصل على دفعة الأداء هذه؟ إنه يعمل أقل لإعطائك نفس الإخراج تقريبًا. تستدعي هذه المكتبة نفس وظائف syscall للقيام بالعمل ، ولكنها تقوم بإجراء عدد أقل من المكالمات ، ولا تتخلص من المعلومات التي قد تحتاجها ، وتنشئ أقل من الذاكرة على طول الطريق عن طريق إعادة استخدام المخزن المؤقت للخدش نفسه للقراءة من دليل بدلاً من إعادة تخصيص مخزن مؤقت جديد في كل مرة يقرأ فيها بيانات إدخال نظام الملفات من نظام التشغيل.
أثناء اجتياز شجرة دليل نظام الملفات ، يحصل filepath.Walk على قائمة أحفاد الدليل المباشر ، ويرمي معلومات نوع العقدة لإدخال نظام الملفات الذي يوفره نظام التشغيل الذي يأتي باسم العقدة. بعد ذلك ، قبل استدعاء وظيفة رد الاتصال ، يستدعي filepath.Walk os.Stat لكل عقدة ، ويمرر معلومات os.FileInfo التي تم إرجاعها إلى رد الاتصال.
على الرغم من أن معلومات os.FileInfo التي توفرها os.Stat مفيدة للغاية-وحتى تتضمن بيانات 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.
عندما يكون لنظام الملفات الذي تم اجتيازه حلقة منطقية ناتجة عن روابط رمزية للدلالات ، فإن على Unix filepath.Walk يتجاهل الروابط الرمزية ويجتدى شجرة الدليل بأكملها دون خطأ. ومع ذلك ، على Windows ، سيستمر filepath.Walk بعد الروابط الرمزية للدليل ، على الرغم من أنه ليس من المفترض أن تسبب في نهاية المطاف filepath.Walk لإنهاء مبكرًا وإعادة خطأ عندما يزداد وقتًا من تسلسل حلقات لا نهاية لها من الروابط الرمزية على المسار. يأتي هذا الخطأ من Windows ، ويمر عبر filepath.Walk ، وإلى العميل المنبع الذي يعمل على تشغيل filepath.Walk .
الوجبات الجاهزة هي أن السلوك مختلف بناءً على النظام الأساسي filepath.Walk . على الرغم من أن هذا ليس مقصودًا بشكل واضح ، إلا أنه يتم إصلاحه في المكتبة القياسية ، إلا أنه يمثل مشكلة توافق.
تقوم هذه المكتبة بإصلاح المشكلة أعلاه بحيث لن تتبع أبدًا حلقات الملف المنطقي على UNIX أو Windows. علاوة على ذلك ، سوف يتبع الروابط الرمزية فقط عندما يتم ضبط FollowSymbolicLinks على صحيح. السلوك على Windows وأنظمة التشغيل الأخرى متطابقة.
filepath.Walk بينما تسعى هذه المكتبة إلى تقليد سلوك مكتبة filepath.Walk القياسية المكتوبة جيدًا بشكل لا يصدق ، هناك أماكن تنحرف فيها قليلاً من أجل توفير واجهة متصل أكثر سهولة أو بديهية.
نظرًا لأن هذه المكتبة لا تستدعي os.Stat على كل عقدة نظام الملفات التي تواجهها ، فلا يوجد حدث خطأ محتمل لتصفية وظيفة رد الاتصال. الوسيطة الثالثة في توقيع وظيفة filepath.WalkFunc لتمرير الخطأ من os.Stat إلى وظيفة رد الاتصال لم يعد ضروريًا ، وبالتالي تم القضاء عليه من توقيع وظيفة رد الاتصال من هذه المكتبة.
علاوة على ذلك ، فإن هذا الفرق الطفيف في الواجهة بين filepath.WalkFunc و WalkFunc من هذه المكتبة يلغي رمز Boilerplate الذي يجب أن يكتبه معالجات رد الاتصال عند استخدام filepath.Walk . بدلاً من كل وظيفة رد اتصال تحتاج إلى التحقق من قيمة الخطأ التي تم تمريرها والفرع وفقًا لذلك ، لا يملك مستخدمو هذه المكتبة قيمة خطأ للتحقق فور الدخول إلى وظيفة رد الاتصال. هذا تحسن في أداء وقت التشغيل ووضوح رمز.
على كل منصة نظام التشغيل filepath.Walk ، يستدعي وظيفة رد الاتصال مع اسم مسار Solidus ( / ) محدد. على النقيض من ذلك ، تستدعي هذه المكتبة رد الاتصال بفاصل PathName الخاص بنظام التشغيل ، مما يؤدي إلى تجنب مكالمة إلى filepath.Clean في وظيفة رد الاتصال لكل عقدة قبل استخدام مسار المسار المقدم.
بمعنى آخر ، حتى على Windows ، سوف تستدعي filepath.Walk رد الاتصال ببعض some/path/to/foo.txt ، مما يتطلب عملاء مكتوبة جيدًا لأداء تطبيع اسم المسار لكل ملف قبل العمل مع الملف المحدد. هذا هو متطلبات مخفية من الغلاية لإنشاء وظائف رد الاتصال غير المحسوسة. في الحقيقة ، تم تطوير العديد من العملاء على UNIX وعدم اختبارهم على Windows يهمل هذا الدقة ، وسيؤدي إلى أخطاء البرامج عندما يحاول شخص ما تشغيل هذا البرنامج على Windows.
تستدعي هذه المكتبة وظيفة رد الاتصال مع somepathtofoo.txt لنفس الملف عند التشغيل على Windows ، والقضاء على الحاجة إلى تطبيع اسم العميل ، وتقليل احتمال أن يعمل العميل على UNIX ولكن ليس على Windows.
هذا التحسين يلغي ضرورة بعض رمز الغلاية في وظائف رد الاتصال مع تحسين أداء وقت التشغيل لهذه المكتبة.
godirwalk.SkipThis أكثر سهولة للاستخدام من filepath.SkipDir أحد الجوانب المربكة من واجهة filepath.WalkFunc التي يجب على هذه المكتبة أن تقودها هي كيف يروي المتصل وظيفة Walk لتخطي إدخالات نظام الملفات. مع كل من filepath.Walk Walk هذه المكتبة ، عندما تريد وظيفة رد الاتصال تخطي دليل وعدم النزول إلى أطفالها ، فإنها تعيد filepath.SkipDir . إذا كانت وظيفة رد الاتصال تُرجع filepath.SkipDir لغير الدليل ، فإن filepath.Walk وستتوقف هذه المكتبة عن معالجة أي إدخالات أخرى في الدليل الحالي. هذا ليس بالضرورة ما يريده معظم المطورين أو يتوقعونه. إذا كنت ترغب ببساطة في تخطي إدخال معين غير دليل ولكنه متابعة معالجة الإدخالات في الدليل ، فيجب أن تعود وظيفة رد الاتصال.
إن الآثار المترتبة على تصميم الواجهة هذه هي عندما تريد المشي تسلسلًا هرميًا لنظام الملفات وتخطي إدخال ، يجب عليك إرجاع قيمة مختلفة بناءً على نوع إدخال نظام الملفات الذي تكون عليه العقدة. لتخطي إدخال ، إذا كان الإدخال دليلًا ، فيجب عليك إرجاع filepath.SkipDir ، وإذا لم يكن الإدخال دليلًا ، فيجب عليك العودة nil . هذه عقبة مؤسفة لاحظتها العديد من المطورين الذين يكافحون معهم ، ببساطة لأنها ليست واجهة بديهية.
فيما يلي وظيفة رد الاتصال التي تلتزم بها واجهة filepath.WalkFunc لجعلها تخطي أي إدخال نظام ملفات يتضمن مساره الكامل فرعية معينة ، optSkip . لاحظ أن هذه المكتبة لا تزال تدعم السلوك المتطابق لـ filepath.Walk عندما تُرجع وظيفة رد الاتصال 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
} تحاول هذه المكتبة إلغاء بعض من هذا المنطق المطلوب في وظائف رد الاتصال من خلال توفير قيمة خطأ رمز جديد ، 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 . ومع ذلك ، فإنه يستدعي وظيفة رد الاتصال مع كل عقدة تجدها ، بما في ذلك الروابط الرمزية. في حالة وجود حالة استخدام معينة لاتباع الروابط الرمزية عند عبور شجرة الدليل ، يمكن استدعاء هذه المكتبة بطريقة للقيام بذلك ، من خلال ضبط معلمة config FollowSymbolicLinks إلى true .
يتمثل السلوك الافتراضي لهذه المكتبة دائمًا في فرز أحفاد الدليل المباشر قبل زيارة كل عقدة ، تمامًا مثل filepath.Walk . هذا هو عادة السلوك المطلوب. ومع ذلك ، فإن هذا يأتي إلى الأداء الطفيف وعقوبات الذاكرة المطلوبة لفرز الأسماء عندما تحتوي عقدة الدليل على العديد من الإدخالات. بالإضافة إلى ذلك ، إذا كان المتصل يحدد التعداد Unsorted في معلمة التكوين ، فسيتم تنفيذ أدلة القراءة بتكاسل حيث يستهلك المتصل إدخالات. في حالة وجود حالة استخدام معينة لا تتطلب فرز أحفاد الدليل الفوري قبل زيارة العقد الخاصة به ، ستتخطى هذه المكتبة خطوة الفرز عند ضبط المعلمة Unsorted على true .
فيما يلي قراءة مثيرة للاهتمام عن Hazzards المحتملة لاجتياز التسلسل الهرمي لنظام الملفات بترتيب غير محدد. إذا كنت تعرف أن المشكلة التي تحلها لا تتأثر بزيارة ملفات الطلب ، فأنا أشجعك على استخدام Unsorted . خلاف ذلك تخطي تعيين هذا الخيار.
يجد الباحثون أن الخلل في نص Python قد أثر على مئات الدراسات
توفر هذه المكتبة رمز المنبع القدرة على تحديد وظيفة رد الاتصال ليتم استدعاءها لكل دليل بعد معالجة أطفالها. تم استخدام هذا لحذف الدلائل الفارغة بشكل متكرر بعد اجتياز نظام الملفات بطريقة أكثر كفاءة. انظر دليل examples/clean-empties للحصول على مثال على هذا الاستخدام.
توفر هذه المكتبة رمز المنبع القدرة على تحديد رد اتصال ليتم استدعاؤه للأخطاء التي يعيدها نظام التشغيل ، مما يسمح للرمز المنبع لتحديد مسار الإجراء التالي الذي يجب اتخاذه ، سواء كان لوقف المشي في التسلسل الهرمي ، كما لو أنه لم يتم توفير عادل للخطأ ، أو تخطي العقدة التي تسببت في الخطأ. راجع دليل examples/walk-fast للحصول على مثال على هذا الاستخدام.