godirwalk es una biblioteca para atravesar un árbol de directorio en un sistema de archivos.
En resumen, ¿por qué creé esta biblioteca?
filepath.Walk .filepath.Walk .filepath.Walk .filepath.Walk .Dependiendo de sus circunstancias específicas, es posible que ya no necesite una biblioteca para caminar archivos en Go.
Se proporcionan ejemplos adicionales en los examples/ subdirectorio.
Esta biblioteca normalizará el nombre del directorio de nivel superior proporcionado basado en el separador de ruta específico del sistema operativo llamando filepath.Clean en su primer argumento. Sin embargo, siempre proporciona el nombre de ruta creado utilizando el separador de ruta específico del sistema operativo correcto al invocar la función de devolución de llamada proporcionada.
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)
}) Esta biblioteca no solo proporciona funciones para atravesar un árbol de directorio del sistema de archivos, sino también para obtener una lista de descendientes inmediatos de un directorio en particular, generalmente mucho más rápido que usar os.ReadDir o os.ReadDirnames .
He aquí por qué uso godirwalk con preferencia a filepath.Walk , os.ReadDir y os.ReadDirnames .
filepath.Walk En comparación con filepath.Walk en puntos de referencia, se ha observado que se ejecuta entre cinco y diez veces la velocidad en Darwin, a velocidades comparables a la de UNIX find Utility; y aproximadamente el doble de la velocidad en Linux; y unas cuatro veces la velocidad en las ventanas.
¿Cómo obtiene este impulso de rendimiento? Hace menos trabajo para darle casi el mismo resultado. Esta biblioteca llama a las mismas funciones syscall para hacer el trabajo, pero hace menos llamadas, no tira información que pueda necesitar, y crea menos rotación de memoria en el camino al reutilizar el mismo búfer de rascar para leer desde un directorio en lugar de reasignar un nuevo búfer cada vez que lee los datos de entrada del sistema de archivos del sistema operativo.
Mientras atraviesa un árbol de directorio del sistema de archivos, filepath.Walk obtiene la lista de descendientes inmediatos de un directorio, y tira la información de tipo de nodo para la entrada del sistema de archivos que proporciona el sistema operativo que viene con el nombre del nodo. Luego, inmediatamente antes de invocar la función de devolución de llamada, filepath.Walk invoca os.Stat para cada nodo, y pasa la información de os.FileInfo devuelta a la devolución de llamada.
Si bien la información de os.FileInfo proporcionada por os.Stat es extremadamente útil, e incluso incluye los datos de os.FileMode , lo que requiere una llamada de sistema adicional para cada nodo.
Debido a que a la mayoría de las devoluciones de llamada solo se preocupan por cuál es el tipo de nodo, esta biblioteca no arroja la información de tipo, sino que proporciona esa información a la función de devolución de llamada en forma de un valor os.FileMode . Tenga en cuenta que el valor os.FileMode proporcionado que proporciona esta biblioteca solo tiene la información de tipo de nodo y no tiene los bits de permiso, bits adhesivos u otra información del modo del archivo. Si la devolución de llamada se preocupa por la estructura de datos os.FileInfo de un nodo particular, la devolución de llamada puede invocar os.Stat cuando sea necesario, y solo cuando sea necesario.
$ 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.WalkAnteriormente tampoco me importaba, pero me humorlo. Todos amamos cómo podemos escribir una vez y correr a todas partes. Es esencial para la adopción, el crecimiento y el éxito del idioma que el software que creamos puede ejecutarse sin modificar en todas las arquitecturas y sistemas operativos compatibles con GO.
Cuando el sistema de archivos atravesado tiene un bucle lógico causado por enlaces simbólicos a directorios, en UNIX filepath.Walk ignora los enlaces simbólicos y atraviesa todo el árbol de directorio sin error. Sin embargo, en Windows, filepath.Walk continuará siguiendo los enlaces simbólicos del directorio, a pesar de que no se supone que debe hacerlo, lo que eventualmente hace que filepath.Walk termine temprano y devuelva un error cuando el nombre de ruta llega demasiado tiempo al concatenar bucles interminables de enlaces simbólicos en el nombre de ruta. Este error proviene de Windows, pasa a través de filepath.Walk y al cliente aguas arriba que ejecuta filepath.Walk .
La conclusión es que el comportamiento es diferente en función de qué plataforma filepath.Walk se está ejecutando. Si bien esto claramente no es intencional, hasta que se solucione en la biblioteca estándar, presenta un problema de compatibilidad.
Esta biblioteca soluciona el problema anterior de modo que nunca seguirá los bucles de Sytem de archivos lógicos en UNIX o Windows. Además, solo seguirá los enlaces simbólicos cuando FollowSymbolicLinks se establecen en verdadero. El comportamiento en Windows y otros sistemas operativos es idéntico.
filepath.Walk Si bien esta biblioteca se esfuerza por imitar el comportamiento de la biblioteca estándar filepath.Walk increíblemente bien escrita, hay lugares donde se desvía un poco para proporcionar una interfaz de llamadas más fácil o intuitiva.
Dado que esta biblioteca no invoca os.Stat en cada nodo del sistema de archivos que encuentra, no hay un evento de error posible para que la función de devolución de llamada se filtre. El tercer argumento en la firma de la función filepath.WalkFunc para pasar el error de os.Stat a la función de devolución de llamada ya no es necesario, y por lo tanto se elimina de la firma de la función de devolución de llamada de esta biblioteca.
Además, esta ligera diferencia de interfaz entre filepath.WalkFunc y WalkFunc de esta biblioteca elimina el código de planta que los controladores de devolución de llamada deben escribir cuando usan filepath.Walk . En lugar de cada función de devolución de llamada que necesita verificar el valor de error que se le pasó y ramificarse en consecuencia, los usuarios de esta biblioteca ni siquiera tienen un valor de error para verificar inmediatamente al ingresar la función de devolución de llamada. Esta es una mejora tanto en el rendimiento del tiempo de ejecución como en la claridad del código.
En cada plataforma del sistema operativo filepath.Walk invoca la función de devolución de llamada con un nombre de ruta delimitado solidus ( / ). Por el contrario, esta biblioteca invoca la devolución de llamada con el separador de rutina específico del sistema operativo, obviando una llamada a filepath.Clean en la función de devolución de llamada para cada nodo antes de usar el nombre de ruta proporcionado.
En otras palabras, incluso en Windows, filepath.Walk invocará la devolución de llamada con some/path/to/foo.txt , lo que requiere que los clientes bien escritos realicen la normalización de PathName para cada archivo antes de trabajar con el archivo especificado. Este es un requisito oculto de Boilerplate para crear verdaderas funciones de devolución de llamada agnóstica del sistema operativo. En verdad, muchos clientes se desarrollaron en UNIX y no probados en Windows descuidan esta sutileza, y darán como resultado errores de software cuando alguien intente ejecutar ese software en Windows.
Esta biblioteca invoca la función de devolución de llamada con somepathtofoo.txt para el mismo archivo cuando se ejecuta en Windows, eliminando la necesidad de normalizar el nombre de ruta por parte del cliente y disminuir la probabilidad de que un cliente trabaje en UNIX pero no en Windows.
Esta mejora elimina la necesidad de más código de calderas en las funciones de devolución de llamada al tiempo que mejora el rendimiento del tiempo de ejecución de esta biblioteca.
godirwalk.SkipThis es más intuitivo de usar que filepath.SkipDir Un aspecto posiblemente confuso de la interfaz filepath.WalkFunc que debe emular esta biblioteca es cómo una persona que llama le dice a la función Walk para omitir las entradas del sistema de archivos. Tanto con filepath.Walk como con Walk de esta biblioteca, cuando una función de devolución de llamada quiere omitir un directorio y no descender a sus hijos, devuelve filepath.SkipDir . Si la función de devolución de llamada devuelve filepath.SkipDir para un no directorio, filepath.Walk y esta biblioteca dejará de procesar más entradas en el directorio actual. Esto no es necesariamente lo que la mayoría de los desarrolladores quieren o esperan. Si simplemente desea omitir una entrada no directorio particular pero continúe procesando entradas en el directorio, la función de devolución de llamada debe devolver nulo.
Las implicaciones de este diseño de interfaz es cuando desea caminar una jerarquía del sistema de archivos y omitir una entrada, debe devolver un valor diferente basado en qué tipo de entrada del sistema de archivos es ese nodo. Para omitir una entrada, si la entrada es un directorio, debe devolver filepath.SkipDir , y si la entrada no es un directorio, debe devolver nil . Este es un obstáculo desafortunado con el que he observado a muchos desarrolladores que luchan, simplemente porque no es una interfaz intuitiva.
Aquí hay una función de devolución de llamada de ejemplo que se adhiere a la interfaz filepath.WalkFunc para que saltea cualquier entrada del sistema de archivos cuyo nombre de ruta completo incluya una subcadena particular, optSkip . Tenga en cuenta que esta biblioteca aún admite un comportamiento idéntico de filepath.Walk cuando la función de devolución de llamada devuelve 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
} Esta biblioteca intenta eliminar parte de esa placa lógica requerida en las funciones de devolución de llamada proporcionando un nuevo valor de error de token, SkipThis , que una función de devolución de llamada puede volver a omitir la entrada del sistema de archivos actual, independientemente de qué tipo de entrada sea. Si la entrada actual es un directorio, sus hijos no serán enumerados, exactamente como si la devolución de llamada hubiera devuelto filepath.SkipDir . Si la entrada actual no es un directorio, la siguiente entrada del sistema de archivos en el directorio actual se enumerará, exactamente como si la devolución de llamada devolviera nil . La siguiente función de devolución de llamada de ejemplo tiene un comportamiento idéntico como el anterior, pero tiene menos calderas, y ciertamente lógica que me parece más fácil de seguir.
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 El comportamiento predeterminado de esta biblioteca es ignorar los enlaces simbólicos a los directorios al caminar un árbol de directorio, al igual que filepath.Walk . Sin embargo, invoca la función de devolución de llamada con cada nodo que encuentra, incluidos los enlaces simbólicos. Si existe un caso de uso particular para seguir enlaces simbólicos al atravesar un árbol de directorio, esta biblioteca se puede invocar de manera para hacerlo, estableciendo el parámetro de configuración FollowSymbolicLinks en true .
El comportamiento predeterminado de esta biblioteca es ordenar siempre a los descendientes inmediatos de un directorio antes de visitar cada nodo, al igual que filepath.Walk . Este suele ser el comportamiento deseado. Sin embargo, esto viene en un ligero rendimiento y sanciones de memoria necesarias para ordenar los nombres cuando un nodo de directorio tiene muchas entradas. Además, si la persona que llama especifica una enumeración Unsorted en el parámetro de configuración, los directorios de lectura se realizan perezosamente cuando la persona que llama consume entradas. Si existe un caso de uso en particular que no requiere clasificar los descendientes inmediatos del directorio antes de visitar sus nodos, esta biblioteca se omitirá el paso de clasificación cuando el parámetro Unsorted se establezca en true .
Aquí hay una lectura interesante de los posibles hazzars de atravesar una jerarquía del sistema de archivos en un orden no determinista. Si sabe que el problema que está resolviendo no se ve afectado por los archivos de pedidos, entonces se les animo a que use Unsorted . De lo contrario, omita la configuración de esta opción.
Los investigadores encuentran que el error en el guión de Python puede haber afectado a cientos de estudios
Esta biblioteca proporciona al código aguas arriba la capacidad de especificar una función de devolución de llamada que se invocará para cada directorio después de que se procesen sus hijos. Esto se ha utilizado para eliminar recursivamente directorios vacíos después de atravesar el sistema de archivos de una manera más eficiente. Consulte el directorio de examples/clean-empties para obtener un ejemplo de este uso.
Esta biblioteca proporciona al código aguas arriba con la capacidad de especificar una devolución de llamada para invocar los errores que el sistema operativo devuelve, lo que permite que el código aguas arriba determine el siguiente curso de acción, ya sea para detener la jerarquía, como lo haría, no se proporcionaron una devolución de llamada de error, o omitir el nodo que causó el error. Vea los examples/walk-fast para obtener un ejemplo de este uso.