Leer archivo de texto en Go

Hay dos formas: os.ReadFile carga el archivo entero, y bufio.Scanner lo lee línea a línea. La segunda tiene un límite que casi nadie conoce, y que hace que el programa deje de leer a mitad sin decir nada si no lo compruebas.

Todo de una vez

datos, err := os.ReadFile("notas.txt")
if err != nil {
	log.Fatal(err)
}
salidaReadFile: 45 bytes, 3 líneas

Devuelve []byte; para tratarlo como texto, string(datos). Para archivos pequeños es lo más cómodo. La versión anterior de esta página usaba ioutil.ReadFile: el paquete ioutil está obsoleto desde Go 1.16 y sus funciones se movieron a os e io.

Línea a línea

f, err := os.Open("notas.txt")
if err != nil {
	log.Fatal(err)
}
defer f.Close()

sc := bufio.NewScanner(f)
n := 0
for sc.Scan() {
	n++
	fmt.Printf("%d: %s\n", n, sc.Text())
}
if err := sc.Err(); err != nil {
	log.Fatal(err)
}
salida1: Primera línea
2: Segunda línea
3: Tercera línea

Scan() avanza a la siguiente línea y devuelve false al llegar al final o si hay un error. Por eso hace falta el sc.Err() de después: es lo único que distingue «terminé» de «me rompí a mitad». Text() devuelve la línea sin el salto final.

El ejemplo anterior imprimía también scanner.Bytes(), y salía una lista de números como [80 114 105 …]: son los mismos caracteres, vistos como bytes. Para texto, Text().

El límite de los 64 KB

Por omisión, Scanner no acepta líneas de más de 64 KB. Con un archivo de una sola línea de 70 KB —un JSON minimizado, un CSV raro— pasa esto:

salidalínea de 70 KB, sin ampliar el búfer: bufio.Scanner: token too long

Y el bucle simplemente termina, como si el archivo se hubiera acabado. Si no compruebas sc.Err(), no te enteras. Se arregla ampliando el búfer antes de leer:

sc := bufio.NewScanner(g)
sc.Buffer(make([]byte, 0, 64*1024), 1024*1024)   // hasta 1 MB por línea
salidacon Buffer(…, 1 MB): leída una línea de 71680 caracteres

Si el archivo no está

_, err = os.Open("no_existe.txt")
fmt.Println(err, errors.Is(err, fs.ErrNotExist))
salidaopen no_existe.txt: no such file or directory true

Para saber si el error es «no existe», errors.Is(err, fs.ErrNotExist). Compara el tipo de error, no el texto, y funciona igual en todos los sistemas operativos.

Más información en inglés: Read text file in Golang.

Todo el código se compiló y se ejecutó con Go 1.27 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.