29 de junio, 2021 - 4 min
Hace unas semanas tuve la necesidad de recorrer miles de archivos y carpetas, leer su contenido y luego contabilizar cuántos de estos cumplían con cierto requerimiento. Al inicio pensaba usar nodejs pero luego de revisar la documentación de cade lenguaje decidí usar golang.
Para esto usaremos el paquete ioutil
, este contiene el método ReadFile
con el que obtendremos el contenido de un archivo.
package main import ( "fmt" "io/ioutil" ) const filePath = "file.txt" func main() { content, err := ioutil.ReadFile(filePath) if err != nil { fmt.Println(err) panic("error to read the file") } text := string(content) fmt.Println("The content file is: ", text) }
Al igual que la sección anterior, también usaremos ioutil
para modificar o sobreescribir el contenido.
Para ello, este contiene un método WriteFile
.
Recuerda que golang creará el archivo en caso este no exista.
package main import ( "fmt" "io/ioutil" ) const filePath = "./file.txt" func main() { // write this to the file newContent := "file was modified" // The thrid param is the perm(ision) mode for the current system // 0600 (rw) means read and write for the Owner of the file // You can use this https://chmod-calculator.com to calculate the last param err := ioutil.WriteFile(filePath, []byte(newContent), 0600) if err != nil { fmt.Println(err) panic("error to write file") } }
Para leer archivos de una carpeta en golang podemos usar la función filepath.WalkDir. Como primer párametro este acepta la ruta de la carpeta y como segundo un callback que se ejecuta por cada carpeta o archivo encontrado.
package main import ( "fmt" "path/filepath" ) const folderPath = "/my/folter/path" func main() { filepath.WalkDir(folderPath, walkDirFunc) fmt.Println("Number of deprecated files: ", func(path string, d fs.DirEntry, err error) error { fmt.Printf("Name of the folder or file is %s", d.Name()) }) }
Demosle un uso práctico a estos 3 métodos dando solución a lo siguiente:
Recorrer de forma recursiva una carpeta que contiene multiples archivos y sub-carpetas. Para cada uno de estos archivos, ejecutar lo siguiente:
Como regla tenemos:
Al final, nuestro programa debería mostrar lo siguiente en la terminal:
Total files with extension .py modified: XXXXX Total files with the "@deprecated" comment: XXXXX
Solución:
package main import ( "fmt" "io/fs" "path/filepath" "os" ) const folderPath = "/my/folter/path" var deprecatedFiles int = 0 var modifiedFiles int = 0 func main() { filepath.WalkDir(folderPath, walkDirFunc) fmt.Println("Total files with extension .py modified: ", modifiedFiles) fmt.Println("Total files with the \"@deprecated\" comment: ", deprecatedFiles) } func walkDirFunc(path string, d fs.DirEntry, err error) error { // ignore tmp folders name := d.Name() if name == "tmp" { // return this constant to skip a folder/file return filepath.SkipDir } fileEx := filepath.Ext(name) // modify .py files if fileEx == ".py" { rawBytes, err := os.ReadFile(path) if err != nil { panic(err) } content := string(rawBytes) newContent := "# file modified" + "\n" + string(fileContent) err = ioutil.WriteFile(path, []byte(newContent), 0644) if err != nil { panic(err) } modifiedFiles = modifiedFiles + 1 } // count files with extension .tsx or .ts that have the @deprecated comment in the top if fileEx == ".ts" || fileEx == ".tsx" { rawBytes, err := ioutil.ReadFile(path) if err != nil { panic(err) } lines := strings.Split(string(rawBytes), "\n") // we only care about the first line firstLine := lines[0] if firstLine == "// @deprecated" { deprecatedFiles = deprecatedFiles + 1 } } return nil }
Como vimos, golang ofrece muchos métodos para poder trabajar con archivos y carpetas. Viniendo del mundo de scripting con nodejs, puedo asegurar que con golang este tipo de tareas es mucho más simple. Espero esta información te sea útil.
¡Gracias por leer!