Enumere los archivos en una carpeta con Go

En este artículo explico cómo obtener una lista de archivos dentro de una carpeta en el sistema de archivos, una tarea también llamadaárbol atravesando, con Go.

Hay dos funciones útiles de stdlib que puede utilizar según su objetivo.

Enumero 3 formas: usandofilepath.Walk,ioutil.ReadDiroos.File.Readdir.

Usandofilepath.Walk

lospath/filepathEl paquete stdlib proporciona la práctica función Walk. Sin embargo, escanea automáticamente los subdirectorios, así que asegúrese de que esto sea lo que realmente desea.

El uso es muy simple:

package main

import ( “fmt” “os” “path/filepath” )

func main() { var files []string

<span style="color:#a6e22e">root</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">"/some/folder/to/scan"</span>
<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#66d9ef">func</span>(<span style="color:#a6e22e">path</span> <span style="color:#66d9ef">string</span>, <span style="color:#a6e22e">info</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">FileInfo</span>, <span style="color:#a6e22e">err</span> <span style="color:#66d9ef">error</span>) <span style="color:#66d9ef">error</span> {
    <span style="color:#a6e22e">files</span> = append(<span style="color:#a6e22e">files</span>, <span style="color:#a6e22e">path</span>)
    <span style="color:#66d9ef">return</span> <span style="color:#66d9ef">nil</span>
})
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>)
}

}

filepath.Walkacepta una cadena que apunta a la carpeta raíz y unaWalkFunc, un tipo de función con firma

type WalkFunc func(path string, info os.FileInfo, err error) error

Esta función se llama para cada iteración del escaneo de carpetas.

losinfovariable de tipoos.FileInfoes importante porque podemos obtener mucha información sobre el archivo actual: el nombre, tamaño, modo, hora de modificación, si es una carpeta o un archivo, y la fuente de datos subyacente.

Por ejemplo, podríamos evitar el procesamiento de carpetas agregando

if info.IsDir() {
    return nil
}

Puede excluir (o incluir) archivos al segmento en función de su extensión, utilizandofilepath.Exty pasando la ruta del archivo:

if filepath.Ext(path) == ".dat" {
    return nil
}

Podríamos almacenar el nombre del archivo en lugar de la ruta del archivo usando

files = append(files, info.Name())

Y también podríamos definir elWalkFuncen un separadocierre. Solo necesitamos pasar un puntero afilesenvisit:

package main

import ( “fmt” “log” “os” “path/filepath” )

func visit(files []string) filepath.WalkFunc { return func(path string, info os.FileInfo, err error) error { if err != nil { log.Fatal(err) } files = append(*files, path) return nil } }

func main() { var files []string

<span style="color:#a6e22e">root</span> <span style="color:#f92672">:=</span> <span style="color:#e6db74">"/some/folder/to/scan"</span>
<span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">filepath</span>.<span style="color:#a6e22e">Walk</span>(<span style="color:#a6e22e">root</span>, <span style="color:#a6e22e">visit</span>(<span style="color:#f92672">&amp;</span><span style="color:#a6e22e">files</span>))
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    panic(<span style="color:#a6e22e">err</span>)
}
<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>)
}

}

Usandoioutil.ReadDir

filepath.Walkes útil, pero también escanea subcarpetas, de forma predeterminada, que puede que no sea lo que desea.

Go stdlib también proporcionaioutil.ReadDir

func ReadDir(dirname string) ([]os.FileInfo, error)

ReadDir lee el directorio nombrado por dirname y devuelve una lista de entradas de directorio ordenadas por nombre de archivo.

y aquí hay un ejemplo de los documentos.ioutil.ReadDirtoma una ruta de carpeta como una cadena y devuelve una porción deos.FileInfo, que describimos anteriormente.

package main

import ( “fmt” “io/ioutil” “log” )

func main() { files, err := ioutil.ReadDir(".") if err != nil { log.Fatal(err) }

<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Name</span>())
}

}

Usandoos.File.Readdir

Internamente,ioutil.ReadDirse implementa como

// ReadDir reads the directory named by dirname and returns
// a list of directory entries sorted by filename.
func ReadDir(dirname string) ([]os.FileInfo, error) {
    f, err := os.Open(dirname)
    if err != nil {
        return nil, err
    }
    list, err := f.Readdir(-1)
    f.Close()
    if err != nil {
        return nil, err
    }
    sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() })
    return list, nil
}

como puedes ver, escaneadirnamey ordena los archivos por nombre. Si no necesita ordenar, también puede usar

package main

import ( “fmt” “log” “os” )

func main() { dirname := “.”

<span style="color:#a6e22e">f</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">os</span>.<span style="color:#a6e22e">Open</span>(<span style="color:#a6e22e">dirname</span>)
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
}
<span style="color:#a6e22e">files</span>, <span style="color:#a6e22e">err</span> <span style="color:#f92672">:=</span> <span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Readdir</span>(<span style="color:#f92672">-</span><span style="color:#ae81ff">1</span>)
<span style="color:#a6e22e">f</span>.<span style="color:#a6e22e">Close</span>()
<span style="color:#66d9ef">if</span> <span style="color:#a6e22e">err</span> <span style="color:#f92672">!=</span> <span style="color:#66d9ef">nil</span> {
    <span style="color:#a6e22e">log</span>.<span style="color:#a6e22e">Fatal</span>(<span style="color:#a6e22e">err</span>)
}

<span style="color:#66d9ef">for</span> <span style="color:#a6e22e">_</span>, <span style="color:#a6e22e">file</span> <span style="color:#f92672">:=</span> <span style="color:#66d9ef">range</span> <span style="color:#a6e22e">files</span> {
    <span style="color:#a6e22e">fmt</span>.<span style="color:#a6e22e">Println</span>(<span style="color:#a6e22e">file</span>.<span style="color:#a6e22e">Name</span>())
}

}


Más tutoriales de go: