godirwalk - это библиотека для пересечения дерева каталогов в файловой системе.
Короче говоря, почему я создал эту библиотеку?
filepath.Walk .filepath.Walk .filepath.Walk .filepath.Walk .В зависимости от ваших конкретных обстоятельств, вам больше не понадобится библиотека для ходьбы от файлов.
Дополнительные примеры приведены в 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 Utility; и примерно вдвое больше скорости на 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 Walk работает. Хотя это явно не преднамеренно, пока не будет зафиксировано в стандартной библиотеке, он представляет проблему совместимости.
Эта библиотека решает вышеуказанную проблему, так что она никогда не будет следить за логическими циклами Sytem Sytem на UNIX или Windows. Кроме того, он будет следовать за символическими ссылками только тогда, когда FollowSymbolicLinks , установлены на True. Поведение в окнах и других операционных системах идентично.
filepath.Walk В то время как эта библиотека стремится имитировать поведение невероятно хорошо написанной filepath.Walk , есть места, где она немного отклоняется, чтобы обеспечить более простой или интуитивно понятный интерфейс вызывающего абонента.
Поскольку эта библиотека не вызывает os.Stat на каждом узле файловой системы, с которой он встречается, не существует возможного события ошибки для функции обратного вызова для фильтрации. Третий аргумент в подписи функции filepath.WalkFunc для передачи ошибки от os.Stat к функции обратного вызова больше не является необходимым и, таким образом, исключен из подписи функции обратного вызова этой библиотеки.
Кроме того, эта небольшая разница в интерфейсе между filepath.WalkFunc и WalkFunc этой библиотеки устраняет код парикматериала, который обработчики обратного вызова должны писать, когда они используют filepath.Walk . Вместо каждой функции обратного вызова, которая должна проверить значение ошибки, передаваемое в нее и соответственно, пользователи этой библиотеки даже не имеют значения ошибки, чтобы проверить сразу после входа в функцию обратного вызова. Это улучшение как в выполнении выполнения, так и в ясности кода.
На каждой платформе ОС filepath.Walk вызывает функцию обратного вызова с помощью склонного пути Solidus ( / ). Напротив, эта библиотека вызывает обратный вызов с помощью OS-специфического разделителя PathName, устранение вызова filepath.Clean в функции обратного вызова для каждого узла до фактического использования предоставленного пути.
Другими словами, даже в Windows filepath.Walk будет вызывать обратный вызов с some/path/to/foo.txt , требуя от хорошо написанных клиентов выполнять нормализацию Pathname для каждого файла до работы с указанным файлом. Это скрытое требование о шаблоне для создания действительно агностических функций обратного вызова ОС. По правде говоря, многие клиенты разработали на UNIX и не протестированные в Windows, пренебрегая этой тонкостью, и приведут к программным ошибкам, когда кто -то пытается запустить это программное обеспечение в Windows.
Эта библиотека вызывает функцию обратного вызова с somepathtofoo.txt для того же файла при запуске в Windows, что устраняет необходимость нормализации pathname клиентом и уменьшит вероятность того, что клиент будет работать на UNIX, но не на Windows.
Это улучшение устраняет необходимость для некоторого большего кода шаблона в функциях обратного вызова, улучшая производительность времени выполнения этой библиотеки.
godirwalk.SkipThis более интуитивно понятно, чем filepath.SkipDir Один, возможно, запутанный аспект интерфейса filepath.WalkFunc , который должна эмулировать эта библиотека, - это то, как вызывающий абонент сообщает функции Walk , чтобы пропустить записи файловой системы. С помощью filepath.Walk и этой библиотеки Walk , когда функция обратного вызова хочет пропустить каталог, а не спуститься в своих детей, она возвращает filepath.SkipDir . Если функция обратного вызова возвращает filepath.SkipDir для неректории, filepath.Walk и эта библиотека прекратит обработку дополнительных записей в текущем каталоге. Это не обязательно то, что большинство разработчиков хотят или ожидают. Если вы хотите просто пропустить определенную негадотную запись, но продолжите обработку записей в каталоге, функция обратного вызова должна вернуть NIL.
Последствия этого дизайна интерфейса - когда вы хотите пройти иерархию файловой системы и пропустить запись, вы должны вернуть другое значение, основываясь на том, какой тип записи файловой системы, этот узел. Чтобы пропустить запись, если запись является каталогом, вы должны вернуть 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 . Тем не менее, он вызывает функцию обратного вызова с каждым узел, который он находит, включая символические ссылки. Если существует конкретный вариант использования, чтобы следовать символическим ссылкам при переселении дерева каталогов, эта библиотека может быть вызвана способом, чтобы сделать это, установив параметр конфигурации FollowSymbolicLinks на true .
Поведение этой библиотеки по умолчанию - всегда сортировать непосредственных потомков каталога перед посещением каждого узла, точно так же, как и filepath.Walk . Обычно это желаемое поведение. Тем не менее, это связано с небольшой производительности и штрафами на память, необходимых для сортировки имен, когда у узла каталога много записей. Кроме того, если Caller указывает Unsorted перечисление в параметре конфигурации, каталоги чтения лениво выполняются, поскольку вызывающий абонент потребляет записи. Если существует конкретный вариант использования, который не требует сортировки непосредственных потомков каталога перед посещением его узлов, эта библиотека пропустит шаг сортировки, когда Unsorted параметр установлен на true .
Вот интересное чтение о потенциальных смазаниях, связанных с прохождением иерархии файловой системы в нетерминированном порядке. Если вы знаете, что проблема, которую вы решаете, не затрагивает файлы заказа, то я призываю вас использовать Unsorted . В противном случае пропустите настройку этой опции.
Исследователи считают, что ошибка в сценарии Python, возможно, повлияла на сотни исследований
Эта библиотека предоставляет вверх по течению код с возможностью указать функцию обратного вызова, которая будет вызвана для каждого каталога после обработки его детей. Это использовалось для рекурсивного удаления пустых каталогов после прохождения файловой системы более эффективным образом. См. Пример примера использования examples/clean-empties .
Эта библиотека предоставляет вверх по течению код с возможностью указать обратный вызов, который будет вызван для ошибок, которые возвращается операционная система, позволяя всплывающему коду определить следующий курс действия, который должен быть принят, независимо от того, следует ли остановить ходьбу иерархии, как это было бы, если бы не было вызовов, или пропустить узел, который вызвал ошибку. Смотрите examples/walk-fast для примера этого использования.