godirwalk é uma biblioteca para atravessar uma árvore de diretório em um sistema de arquivos.
Em suma, por que eu criei essa biblioteca?
filepath.Walk .filepath.Walk .filepath.Walk .filepath.Walk .Dependendo de suas circunstâncias específicas, você não precisa mais de uma biblioteca para a entrada de arquivos.
Exemplos adicionais são fornecidos nos examples/ subdiretório.
Esta biblioteca normalizará o nome do diretório de nível superior fornecido com base no separador de caminho específico do OS, chamando filepath.Clean em seu primeiro argumento. No entanto, ele sempre fornece o nome do caminho criado usando o separador de caminho específico do OS correto ao invocar a função de retorno de chamada fornecida.
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 não apenas fornece funções para atravessar uma árvore de diretório de sistemas de arquivos, mas também para obter uma lista de descendentes imediatos de um diretório específico, normalmente muito mais rapidamente do que usar os.ReadDir ou os.ReadDirnames .
Eis por que eu uso godirwalk em preferência a filepath.Walk , os.ReadDir e os.ReadDirnames .
filepath.Walk Quando comparado com filepath.Walk em benchmarks, foi observado que corre entre cinco e dez vezes a velocidade em Darwin, a velocidades comparáveis às do utilidade do find ; e cerca de duas vezes a velocidade no Linux; E cerca de quatro vezes a velocidade nas janelas.
Como isso obtém esse impulso de desempenho? Faz menos trabalho para fornecer quase a mesma saída. Esta biblioteca chama as mesmas funções syscall para fazer o trabalho, mas faz menos chamadas, não joga fora informações que ela pode precisar e cria menos rotatividade de memória ao longo do caminho, reutilizando o mesmo buffer de arranhões para ler um diretório em vez de realocar um novo buffer sempre leu os dados de entrada do sistema de arquivos do sistema operacional.
Ao atravessar uma árvore do diretório do sistema de arquivos, filepath.Walk obtém a lista de descendentes imediatos de um diretório e joga fora as informações do tipo de nó para a entrada do sistema de arquivos fornecida pelo sistema operacional que vem com o nome do nó. Em seguida, imediatamente antes de chamar a função de retorno de chamada, filepath.Walk invoca os.Stat para cada nó e passa as informações os.FileInfo retornadas para o retorno de chamada.
Embora as informações os.FileInfo fornecidas pelo os.Stat sejam extremamente úteis-e até incluem os dados os.FileMode -o fornecimento requer uma chamada de sistema adicional para cada nó.
Como a maioria dos retornos de chamada se preocupa apenas com o que é o tipo de nó, essa biblioteca não joga fora as informações do tipo, mas fornece essas informações à função de retorno de chamada na forma de um valor os.FileMode . Observe que o valor os.FileMode fornecido fornecido que esta biblioteca fornece apenas as informações do tipo de nó e não possui os bits de permissão, bits pegajosos ou outras informações do modo do arquivo. Se o retorno de chamada se preocupar com a estrutura de dados os.FileInfo inteira de um nó específico, o retorno de chamada poderá invocar os.Stat quando necessário, e somente quando necessário.
$ 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.WalkEu também não me importava com isso, mas me humor. Todos nós amamos como podemos escrever uma vez e correr por toda parte. É essencial para a adoção, crescimento e sucesso do idioma que o software que criamos pode ser executado não modificado em todas as arquiteturas e sistemas operacionais suportados pelo GO.
Quando o sistema de arquivos atravessado possui um loop lógico causado por links simbólicos para os diretórios, no Unix filepath.Walk ignora links simbólicos e atravessa toda a árvore do diretório sem erro. No Windows, no entanto, filepath.Walk continuará seguindo os links simbólicos do diretório, mesmo que não deva, eventualmente, causando o final filepath.Walk . Esse erro vem do Windows, passa pelo filepath.Walk e para o cliente upstream executando filepath.Walk .
O take -away é que o comportamento é diferente com base em qual plataforma filepath.Walk está em execução. Embora isso claramente não seja intencional, até que seja corrigido na biblioteca padrão, apresenta um problema de compatibilidade.
Esta biblioteca corrige o problema acima, de modo que nunca seguirá loops de sistema de arquivo lógico no UNIX ou Windows. Além disso, ele seguirá apenas os links simbólicos quando FollowSymbolicLinks estiver definido como true. O comportamento no Windows e em outros sistemas operacionais é idêntico.
filepath.Walk Embora essa biblioteca se esforce para imitar o comportamento da filepath.Walk padrão incrivelmente bem escrita.
Como esta biblioteca não invoca os.Stat em todos os nó do sistema de arquivos Encontros, não há um evento de erro possível para a função de retorno de chamada para filtrar. O terceiro argumento na assinatura da função filepath.WalkFunc para passar o erro do os.Stat para a função de retorno de chamada não é mais necessário e, portanto, eliminado da assinatura da função de retorno de chamada desta biblioteca.
Além disso, essa ligeira diferença de interface entre filepath.WalkFunc e WalkFunc desta biblioteca elimina o código da caldeira que os manipuladores de retorno de chamada devem escrever quando usam filepath.Walk . Em vez de todas as funções de retorno de chamada que precisam verificar o valor de erro passadas para ele e ramificar de acordo, os usuários desta biblioteca nem sequer têm um valor de erro para verificar imediatamente após a entrada na função de retorno de chamada. Esta é uma melhoria no desempenho de tempo de execução e na clareza do código.
Em todas as plataformas do sistema operacional filepath.Walk chama a função de retorno de chamada com um nome de caminho Solidus ( / ) delimitado. Por outro lado, esta biblioteca chama o retorno de chamada com o separador de nome do caminho específico do OS, evitando uma chamada para filepath.Clean na função de retorno de chamada para cada nó antes de realmente usar o nome da PathName fornecido.
Em outras palavras, mesmo no Windows, filepath.Walk invocará o retorno de chamada com some/path/to/foo.txt , exigindo que os clientes bem escritos realizassem a normalização do nome do caminho para cada arquivo antes de trabalhar com o arquivo especificado. Este é um requisito de caldeira oculto para criar funções de retorno de chamada agnóstico verdadeiramente OS. Na verdade, muitos clientes desenvolvidos no Unix e não testados no Windows negligenciam essa sutileza e resultam em bugs de software quando alguém tentar executar esse software no Windows.
Esta biblioteca chama a função de retorno de chamada com somepathtofoo.txt para o mesmo arquivo ao executar no Windows, eliminando a necessidade de normalizar o nome do caminho pelo cliente e diminuir a provável que um cliente funcione no Unix, mas não no Windows.
Esse aprimoramento elimina a necessidade de algum código mais caldeiro nas funções de retorno de chamada, melhorando o desempenho do tempo de execução dessa biblioteca.
godirwalk.SkipThis é mais intuitivo de usar do que filepath.SkipDir Um aspecto indiscutivelmente confuso da interface filepath.WalkFunc que essa biblioteca deve imitar é como um chamador informa à função Walk para pular entradas do sistema de arquivos. Com filepath.Walk e Walk desta biblioteca, quando uma função de retorno de chamada deseja pular um diretório e não descer para seus filhos, ele retorna filepath.SkipDir . Se a função de retorno de chamada retornar filepath.SkipDir para um não-diretório, filepath.Walk e esta biblioteca interromperão o processamento mais entradas no diretório atual. Isso não é necessariamente o que a maioria dos desenvolvedores deseja ou espera. Se você deseja simplesmente pular uma entrada específica de não-diretório, mas continue processando entradas no diretório, a função de retorno de chamada deve retornar nulo.
As implicações desse design de interface é quando você deseja percorrer uma hierarquia do sistema de arquivos e pular uma entrada, você deve retornar um valor diferente com base no tipo de entrada do sistema de arquivos esse nó. Para pular uma entrada, se a entrada for um diretório, você deverá retornar filepath.SkipDir e, se a entrada não for um diretório, você deverá retornar nil . Este é um obstáculo infeliz com o qual observei muitos desenvolvedores lutando, simplesmente porque não é uma interface intuitiva.
Aqui está um exemplo de função de retorno de chamada que adere à interface filepath.WalkFunc para que ela ignore qualquer entrada do sistema de arquivos cujo nome completo inclui uma substring específica, optSkip . Observe que esta biblioteca ainda suporta comportamento idêntico do filepath.Walk quando a função de retorno de chamada retorna 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 tenta eliminar parte desse placa de caldeira lógica necessária nas funções de retorno de chamada, fornecendo um novo valor de erro de token, SkipThis , que uma função de retorno de chamada pode retornar para pular a entrada atual do sistema de arquivos, independentemente do tipo de entrada. Se a entrada atual for um diretório, seus filhos não serão enumerados, exatamente como se o retorno de chamada tivesse retornado filepath.SkipDir . Se a entrada atual for um não diretório, a próxima entrada do sistema de arquivos no diretório atual será enumerada, exatamente como se o retorno de chamada retornasse nil . O exemplo a seguir a função de retorno de chamada tem um comportamento idêntico como o anterior, mas tem menos caldeira e reconhecidamente lógica que acho mais simples 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 O comportamento padrão desta biblioteca é ignorar os links simbólicos para os diretórios ao caminhar uma árvore de diretórios, assim como filepath.Walk . No entanto, ele chama a função de retorno de chamada com cada nó que encontra, incluindo links simbólicos. Se existir um caso de uso específico para seguir os links simbólicos ao atravessar uma árvore de diretórios, essa biblioteca pode ser invocada de maneira a fazê -lo, definindo o parâmetro de configuração FollowSymbolicLinks como true .
O comportamento padrão dessa biblioteca é sempre classificar os descendentes imediatos de um diretório antes de visitar cada nó, assim como filepath.Walk . Esse geralmente é o comportamento desejado. No entanto, isso ocorre com pequenas penalidades de desempenho e memória necessárias para classificar os nomes quando um nó de diretório tiver muitas entradas. Além disso, se o chamador especificar a enumeração Unsorted no parâmetro de configuração, os diretórios de leitura são realizados preguiçosamente à medida que o chamador consome entradas. Se existir um caso de uso específico que não exija a classificação dos descendentes imediatos do diretório antes de visitar seus nós, essa biblioteca pulará a etapa de classificação quando o parâmetro Unsorted for definido como true .
Aqui está uma leitura interessante dos hazzards em potencial de atravessar uma hierarquia do sistema de arquivos em uma ordem não determinística. Se você souber o problema que está resolvendo não é afetado pelos arquivos de pedido, encorajo -o a usar Unsorted . Caso contrário, pule a configuração desta opção.
Os pesquisadores encontram bug no script python podem ter afetado centenas de estudos
Esta biblioteca fornece código upstream com a capacidade de especificar uma função de retorno de chamada a ser invocada para cada diretório após o processamento de seus filhos. Isso foi usado para excluir recursivamente os diretórios vazios depois de atravessar o sistema de arquivos de uma maneira mais eficiente. Consulte os examples/clean-empties para um exemplo desse uso.
Esta biblioteca fornece código upstream com a capacidade de especificar um retorno de chamada a ser chamado de erros que o sistema operacional retorna, permitindo que o código a montante determine o próximo curso de ação a ser realizado, para parar a caminhada da hierarquia, como não seria um retorno de chamada de erro, ou pular o nó que causou o erro. Consulte os examples/walk-fast para um exemplo desse uso.