os, io, bufio y path/filepath
La E/S de archivos y flujos en Go organiza pequeñas interfaces en canalizaciones componibles.
Busca en todas las páginas de la documentación
La E/S de archivos y flujos en Go organiza pequeñas interfaces en canalizaciones componibles.
os habla con el sistema de archivos, io define el movimiento de bytes, bufio reduce la sobrecarga de llamadas al sistema y path/filepath construye rutas portátiles.
La mayoría de los programas de Go leen configuraciones, sirven cargas o canalizan datos entre procesos.
La biblioteca estándar modela todo eso como implementaciones de io.Reader y io.Writer.
os.Open devuelve un *os.File que puedes pasar a io.Copy, bufio.NewScanner o json.NewDecoder.
Las herramientas multiplataforma nunca deben codificar / o \ de forma rígida; filepath.Join elige el separador correcto.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
path := filepath.Join("data", "input.txt")
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
var out bytes.Buffer
if _, err := io.Copy(&out, f); err != nil {
return err
}Cuándo usar esto:
bufio.Scanner.package main
import (
"bufio"
"fmt"
"io"
"os"
"path/filepath"
"strings"
)
func copyFiltered(srcPath, dstPath, prefix string) (int, error) {
srcPath = filepath.Clean(srcPath)
dstPath = filepath.Clean(dstPath)
src, err := os.Open(srcPath)
if err != nil {
return 0, fmt.Errorf("abrir src: %w", err)
}
defer src.Close()
if err := os.MkdirAll(filepath.Dir(dstPath), 0o755); err != nil {
return 0, fmt.Errorf("mkdir: %w", err)
}
dst, err := os.Create(dstPath)
if err != nil {
return 0, fmt.Errorf("crear dst: %w", err)
}
defer func() {
if cerr := dst.Close(); cerr != nil && err == nil {
err = cerr
}
}()
scanner := bufio.NewScanner(src)
writer := bufio.NewWriter(dst)
defer writer.Flush()
lines := 0
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, prefix) {
if _, err := writer.WriteString(line + "\n"); err != nil {
return lines, err
}
lines++
}
}
if err := scanner.Err(); err != nil {
return lines, err
}
return lines, nil
}
func main() {
n, err := copyFiltered("input.log", filepath.Join("out", "filtered.log"), "ERR")
if err != nil {
panic(err)
}
fmt.Println("líneas escritas:", n)
}Lo que esto demuestra:
filepath.Clean y filepath.Join para ensamblar rutas de forma segura.os.MkdirAll antes de crear archivos de salida anidados.bufio.Scanner para iteración de línea y bufio.Writer para escrituras por lotes.io.Copy lee de cualquier Reader y escribe en cualquier Writer utilizando un grupo de búferes interno.*os.File se mapean a descriptores de archivo del sistema operativo; los desplazamientos se rastrean por identificador.bufio.Reader y bufio.Writer envuelven flujos para agrupar llamadas al sistema.filepath opera sobre rutas como cadenas; no accede al sistema de archivos (usa os para eso).| Paquete | Responsabilidad | Puntos de entrada típicos |
|---|---|---|
os | Archivos, entorno, proceso, argumentos | Open, ReadFile, WriteFile, Getenv |
io | Contratos y ayudantes de flujo | Copy, ReadAll, LimitReader, Pipe |
bufio | Almacenamiento en búfer y escaneo | NewScanner, NewReader, NewWriter |
path/filepath | Operaciones de ruta específicas del SO | Join, Clean, Walk, Rel |
// Prefiere io.Copy sobre bucles Read manuales para canalizar.
// Limita las cargas para evitar el agotamiento de memoria:
limited := io.LimitReader(r.Body, 1<<20) // Límite de 1 MiB
// Recorre árboles de directorios de forma portátil:
filepath.WalkDir(root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
// procesar archivo
return nil
})defer f.Close() y propagar errores de cierre en los escritores.path en lugar de path/filepath - path es para rutas con barras inclinadas hacia adelante, similares a las URL, no para rutas del sistema de archivos de Windows. Solución: importar path/filepath para rutas del SO.Scanner.Err() - El bucle termina silenciosamente en errores de E/S. Solución: verificar sc.Err() después de for sc.Scan().sc.Buffer(make([]byte, 0, 64*1024), maxToken).Read llena el búfer - Read puede devolver n < len(buf) con un error nil. Solución: bucle hasta io.EOF o usar io.ReadFull.os.Stat y luego os.Open - El archivo puede cambiar entre verificaciones. Solución: abrir primero, luego validar el contenido o usar bloqueos de archivos cuando sea necesario.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
os.ReadFile / os.WriteFile | Archivos pequeños y delimitados | Transmitir cargas grandes o registros |
mmap a través de syscall o de terceros | Lectura de cero copias de archivos enormes | La portabilidad y la simplicidad son más importantes |
embed.FS | Incluir activos estáticos en binarios | Rutas proporcionadas por el usuario en disco |
Abstracciones afero o io/fs | Probar el sistema de archivos sin disco | Herramientas CLI simples solo con archivos reales |
io.Reader es una interfaz con un método Read.
*os.File implementa io.Reader (y io.Writer) para flujos respaldados por el sistema de archivos.
Las funciones que aceptan io.Reader funcionan con archivos, cuerpos de red, cadenas y búferes por igual.
Usa bufio cuando realices muchas lecturas o escrituras pequeñas y desees menos llamadas al sistema.
Usa lecturas directas cuando ya tengas búferes grandes o datos mapeados en memoria.
Join inserta el separador correcto para el SO y limpia elementos redundantes.
La concatenación manual falla en Windows e introduce errores de doble barra inclinada.
Clean simplifica los segmentos . y .. pero no valida la confianza.
Valida las raíces de entrada del usuario por separado antes de abrir archivos.
data, err := os.ReadFile(path) luego string(data).
Para archivos grandes, transmite con bufio.Scanner o io.Copy en su lugar.
Usa el mínimo necesario; 0o600 para configuración privada, 0o644 para artefactos legibles por todos.
Nunca uses 0777 por defecto en el código de la aplicación.
Sí.
Llama a sc.Split con una función SplitFunc personalizada o usa bufio.NewReader con ReadString.
Lee una vez en un búfer, o usa io.TeeReader para copiar bytes a un escritor secundario mientras lees.
No existe un Reader de distribución incorporado.
Los errores de cierre se ignoran a menos que los asignes en una clausura diferida.
Los escritores, en particular, necesitan verificaciones de errores de cierre para vaciar los búferes.
Al aceptar flujos de entrada no confiables (cargas HTTP, cuerpos RPC) para limitar el uso de memoria y CPU.
Combina con verificaciones de tamaño máximo antes de io.ReadAll.
Sí, para directorios de trabajo temporal que hayas creado.
Nunca apuntes RemoveAll a rutas proporcionadas por el usuario sin validar que permanezcan bajo una raíz esperada.
filepath.WalkDir pasa os.DirEntry sin llamadas Stat adicionales, lo que reduce las llamadas al sistema en árboles grandes.
Prefiere WalkDir en código nuevo.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (GC predeterminado de Green Tea, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación) y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026