Todo esto está en el paquete os y son llamadas de una línea. Lo único que conviene entender bien son dos parejas que se confunden: Remove frente a RemoveAll, y copiar cargando el archivo en memoria frente a copiarlo por trozos.
También te puede interesar
Copiar
Si el archivo es pequeño, dos líneas:
b, err := os.ReadFile("original.txt")
if err != nil {
return err
}
err = os.WriteFile("copia.txt", b, 0644)
Pero eso carga el archivo entero en memoria. Con uno grande hay que copiarlo por trozos, y io.Copy lo hace solo:
func copiar(origen, destino string) error {
o, err := os.Open(origen)
if err != nil {
return fmt.Errorf("abriendo %s: %w", origen, err)
}
defer o.Close()
d, err := os.Create(destino)
if err != nil {
return fmt.Errorf("creando %s: %w", destino, err)
}
defer d.Close()
if _, err := io.Copy(d, o); err != nil {
return fmt.Errorf("copiando a %s: %w", destino, err)
}
return d.Sync()
}
io.Copy va leyendo y escribiendo en bloques, así que la memoria que usa no depende del tamaño del archivo. El Sync() del final fuerza el volcado a disco, que es lo que quieres si lo siguiente que va a pasar es apagar la máquina o mover el archivo.
Renombrar y mover
os.Rename("copia.txt", "renombrado.txt") // cambiar el nombre
os.Rename("copia2.txt", "respaldo/copia2.txt") // moverlo de carpeta
Es la misma función: mover es renombrar con otra ruta. Y es una operación atómica… mientras no cruces de sistema de archivos. Si el origen y el destino están en discos distintos, Rename falla y hay que copiar y borrar a mano.
Borrar
fmt.Println(os.Remove("renombrado.txt"))
fmt.Println(os.Remove("fantasma.txt"))
fmt.Println(errors.Is(os.Remove("fantasma.txt"), fs.ErrNotExist))
salida<nil> remove fantasma.txt: no such file or directory true
Borrar algo que no existe sí es un error en Go, al contrario que en otros lenguajes. Si en tu caso eso da igual, se distingue con errors.Is(err, fs.ErrNotExist) en vez de ignorar el error entero.
Remove o RemoveAll
fmt.Println(os.Remove("respaldo")) // una carpeta con cosas dentro
fmt.Println(os.RemoveAll("respaldo"))
fmt.Println(os.RemoveAll("respaldo")) // y otra vez, ya borrada
salidaremove respaldo: directory not empty <nil> <nil>
RemoveAll borra la carpeta con todo lo que tenga dentro, recursivamente y sin preguntar. Y además no se queja si no existe: devuelve nil. Eso lo hace cómodo para limpiar, y peligroso si la ruta viene de una variable que podría estar vacía.¿Existe?
if _, err := os.Stat(ruta); err == nil {
// existe
} else if errors.Is(err, fs.ErrNotExist) {
// no existe
} else {
// existe pero algo falla: permisos, por ejemplo
}
salidaoriginal.txt existe=true fantasma.txt existe=false
Fíjate en la tercera rama. «No pude mirarlo» no es lo mismo que «no está», y confundirlos es el origen de bastantes errores raros.
Resumen
| Para | Usa |
|---|---|
| Copiar algo pequeño | os.ReadFile + os.WriteFile |
| Copiar algo grande | io.Copy entre dos *os.File |
| Renombrar o mover | os.Rename |
| Borrar un archivo o una carpeta vacía | os.Remove |
| Borrar una carpeta con contenido | os.RemoveAll, con cuidado |
| Saber si existe | os.Stat + errors.Is(err, fs.ErrNotExist) |
Todo el código se compiló y ejecutó con Go 1.25 antes de publicarla; las salidas y los mensajes de error están copiados de esa ejecución. Documentación oficial: paquete os.