você precisa passar pela árvore de diretórios recursivamente?
newacct
Respostas:
194
EDIT : Muitas pessoas ainda acertaram esta resposta, que pensei em atualizá-lo para a API Go1. Este é um exemplo funcional de filepath.Walk () . O original está abaixo.
package main
import("path/filepath""os""flag""fmt")
func visit(path string, f os.FileInfo, err error) error {
fmt.Printf("Visited: %s\n", path)returnnil}
func main(){
flag.Parse()
root := flag.Arg(0)
err := filepath.Walk(root, visit)
fmt.Printf("filepath.Walk() returned %v\n", err)}
Observe que filepath.Walk percorre a árvore de diretórios recursivamente.
Este é um exemplo de execução:
$ mkdir -p dir1/dir2
$ touch dir1/file1 dir1/dir2/file2
$ go run walk.go dir1
Visited: dir1
Visited: dir1/dir2
Visited: dir1/dir2/file2
Visited: dir1/file1
filepath.Walk() returned <nil>
SEGUE RESPOSTA ORIGINAL: A interface para percorrer caminhos de arquivo mudou desde a semana de 2011-2011-09-16, consulte http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . O código abaixo não funcionará para versões de lançamento do GO em um futuro próximo.
Na verdade, há uma função na biblioteca padrão apenas para isso: filepath.Walk .
package main
import("path/filepath""os""flag")
type visitor int// THIS CODE NO LONGER WORKS, PLEASE SEE ABOVE
func (v visitor)VisitDir(path string, f *os.FileInfo)bool{
println(path)returntrue}
func (v visitor)VisitFile(path string, f *os.FileInfo){
println(path)}
func main(){
root := flag.Arg(0)
filepath.Walk(root, visitor(0),nil)}
filepath.Walknão segue links simbólicos pelo caminho.
0xcaff
3
O filepath.Walkretorno de chamada @FrancescoPasa será acionado em links simbólicos (arquivo e diretório). Sim, ele não os seguirá , mas o retorno de chamada reconhece um link simbólico e executa outras ações, ou seja, um acompanhamento filepath.Walkgarantindo primeiro que o caminho ainda não foi visitado.
colm.anseo
15
Esta é uma maneira de obter informações sobre os arquivos de um diretório.
@peterSO: o que Readdir (-1) significa? como o Readdir só aceita o tipo de string, e com base na documentação da API, uma string não pode ser NUL, e nenhuma outra limitação .. e qual é o tipo de retorno do "fi" no Readdir como é que pode ser percorrido (é um mapa?) ..
sateayam
@heike: Veja minha resposta revisada, que agora inclui a documentação da API. Como você pode ver, o Readdirparâmetro do método é num int. Se n <= 0, Readdirretorna todos os FileInfodo diretório em uma única fatia.
não seja exigente, mas seu adiamento de fechamento deve ocorrer antes da verificação de erro.
Zanven de
13
Aqui está um exemplo para percorrer todos os arquivos e diretórios recursivamente. Observe que se você quiser saber se o caminho que está acrescentando é um diretório, basta marcar "f.IsDir ()".
Você copiou e colou uma função? O mainmétodo não deve ter ([]string, error)args e você precisa fazer algo com ele err. A menos que na hora da resposta fosse válido? Definitivamente, um erro de compilação em versões mais recentes. Caso contrário, muito útil, obrigado.
Steve
7
O pacote github.com/kr/fsfornece uma WalkerAPI muito interessante.
O pacote padrão Go ioutiltem uma função incorporada para este cenário de caso, veja o exemplo abaixo
func searchFiles(dir string){// dir is the parent directory you what to search
files, err := ioutil.ReadDir(dir)if err !=nil{
log.Fatal(err)}for _, file := range files {
fmt.Println(file.Name())}}
Observe que "Walk não segue links simbólicos", portanto, se você deseja escrever uma função que faça isso, recomendo ioutil.ReadDir . Meu próprio teste de benchmark mostrou que é mais rápido e consome menos memória do que filepath.Glob .
Além disso, ioutil.ReadDirestá classificando os arquivos por nome de base usando comparação de strings básicas ( strA > strB). Como um cara de devops, geralmente classifico nomes de dir fazendo uma comparação numérica reversa (última compilação primeiro, por exemplo). Se esse também for o seu caso, é melhor chamar os.ReadDir diretamente ( ioutil.ReadDirestá chamando isso nos bastidores ) e fazer a classificação você mesmo.
Aqui está um exemplo da ReadDirparte com classificação numérica:
// ReadDirNumSort - Same as ioutil/ReadDir but uses returns a Numerically// Sorted file list.//// Taken from https://golang.org/src/io/ioutil/ioutil.go// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.//// Modified Sort method to use Numerically sorted names instead.// It also allows reverse sorting.
func ReadDirNumSort(dirname string, reverse bool)([]os.FileInfo, error){
f, err := os.Open(dirname)if err !=nil{returnnil, err
}
list, err := f.Readdir(-1)
f.Close()if err !=nil{returnnil, err
}if reverse {
sort.Sort(sort.Reverse(byName(list)))}else{
sort.Sort(byName(list))}return list,nil}// byName implements sort.Interface.
type byName []os.FileInfo
func (f byName)Len()int{return len(f)}
func (f byName)Swap(i, j int){ f[i], f[j]= f[j], f[i]}
func (f byName)Less(i, j int)bool{
nai, err := strconv.Atoi(f[i].Name())if err !=nil{return f[i].Name()< f[j].Name()}
naj, err := strconv.Atoi(f[j].Name())if err !=nil{return f[i].Name()< f[j].Name()}return nai < naj
}
Você pode querer fazer o currying de funções aqui, para que possa utilizar totalmente a pesquisa
func visit(files *[]string) filepath.WalkFunc{return func (path string, info os.FileInfo, err error) error {// maybe do this in some if block*files = append(*files, path)returnnil}}
Respostas:
EDIT : Muitas pessoas ainda acertaram esta resposta, que pensei em atualizá-lo para a API Go1. Este é um exemplo funcional de filepath.Walk () . O original está abaixo.
Observe que filepath.Walk percorre a árvore de diretórios recursivamente.
Este é um exemplo de execução:
SEGUE RESPOSTA ORIGINAL: A interface para percorrer caminhos de arquivo mudou desde a semana de 2011-2011-09-16, consulte http://groups.google.com/group/golang-nuts/msg/e304dd9cf196a218 . O código abaixo não funcionará para versões de lançamento do GO em um futuro próximo.
Na verdade, há uma função na biblioteca padrão apenas para isso: filepath.Walk .
fonte
filepath.Walk
não segue links simbólicos pelo caminho.filepath.Walk
retorno de chamada @FrancescoPasa será acionado em links simbólicos (arquivo e diretório). Sim, ele não os seguirá , mas o retorno de chamada reconhece um link simbólico e executa outras ações, ou seja, um acompanhamentofilepath.Walk
garantindo primeiro que o caminho ainda não foi visitado.Esta é uma maneira de obter informações sobre os arquivos de um diretório.
fonte
Readdir
parâmetro do método én
umint
. Sen <= 0
,Readdir
retorna todos osFileInfo
do diretório em uma única fatia.os
func (FileMode) IsRegular
.Aqui está um exemplo para percorrer todos os arquivos e diretórios recursivamente. Observe que se você quiser saber se o caminho que está acrescentando é um diretório, basta marcar "f.IsDir ()".
fonte
main
método não deve ter([]string, error)
args e você precisa fazer algo com eleerr
. A menos que na hora da resposta fosse válido? Definitivamente, um erro de compilação em versões mais recentes. Caso contrário, muito útil, obrigado.O pacote
github.com/kr/fs
fornece umaWalker
API muito interessante.fonte
O pacote padrão Go
ioutil
tem uma função incorporada para este cenário de caso, veja o exemplo abaixofonte
Observe que "Walk não segue links simbólicos", portanto, se você deseja escrever uma função que faça isso, recomendo ioutil.ReadDir . Meu próprio teste de benchmark mostrou que é mais rápido e consome menos memória do que filepath.Glob .
Além disso,
ioutil.ReadDir
está classificando os arquivos por nome de base usando comparação de strings básicas (strA > strB
). Como um cara de devops, geralmente classifico nomes de dir fazendo uma comparação numérica reversa (última compilação primeiro, por exemplo). Se esse também for o seu caso, é melhor chamar os.ReadDir diretamente (ioutil.ReadDir
está chamando isso nos bastidores ) e fazer a classificação você mesmo.Aqui está um exemplo da
ReadDir
parte com classificação numérica:fonte
Você pode querer fazer o currying de funções aqui, para que possa utilizar totalmente a pesquisa
fonte